type-inference #39

Open
alex-eg wants to merge 17 commits from type-inference into main
10 changed files with 622 additions and 41 deletions
Showing only changes of commit 8a3f51e833 - Show all commits

View File

@@ -94,7 +94,7 @@ sextest:
cp ./tools/sextest/sextest . cp ./tools/sextest/sextest .
SEX_TEST_PROGRAMS = hello-world lists comments unicode serialize features \ SEX_TEST_PROGRAMS = hello-world lists comments unicode serialize features \
feature-flags lambdas compound-literals feature-flags lambdas compound-literals closures fixpoint
# Multi-module linking is checked end to end; see tests/modules/Makefile. # Multi-module linking is checked end to end; see tests/modules/Makefile.
Review

Re 351. One per line, alphabetical. e87463b.

Re 351. One per line, alphabetical. e87463b.
check-modules: sexc check-modules: sexc

View File

@@ -3,6 +3,12 @@
(fn sum ((a int) (b int)) int (fn sum ((a int) (b int)) int
(return (+ a b))) (return (+ a b)))
;;; A lambda captures nothing and is a bare function pointer; a closure
;;; captures and is a value carrying its own environment
(fn make-adder ((a int)) (closure ((int)) int)
(return (closure ((b int)) int (a)
(return (+ a b)))))
(pub fn main () int (pub fn main () int
(var a int 10) (var a int 10)
(var b int 20) (var b int 20)
@@ -36,13 +42,7 @@
(return (+ 600 (l-2 a))))) (return (+ 600 (l-2 a)))))
(printf "Calling nested lambdas: %d\n" (l-1 6)) (printf "Calling nested lambdas: %d\n" (l-1 6))
;; Not supported yet -- captures belong to `closure' now, see (var add-10 (closure ((int)) int) (make-adder 10))
;; Function-values.org (var add-20 (closure ((int)) int) (make-adder 20))
;; (fn make-adder ((a int)) (closure ((int)) int) (printf "Calling closures: %d %d\n" (add-10 24) (add-20 24))
;; (return (closure ((b int)) int (a)
;; (return (+ a b)))))
;;
;; (var add-10 (closure ((int)) int) (make-adder 10))
;; (var add-20 (closure ((int)) int) (make-adder 20))
;; (printf "Calling closures: %d %d\n" (add-10 24) (add-20 24))
(return 0)) (return 0))

395
semen.scm
View File

@@ -17,6 +17,7 @@
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
) )
(export/rename (process semen-process)) (export/rename (process semen-process))
(export closure-env-declaration)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; for lambda extraction, docstring processing, macro expansion, ;;; for lambda extraction, docstring processing, macro expansion,
;;; injection of module headers, i.e. all things that rearrange code ;;; injection of module headers, i.e. all things that rearrange code
@@ -37,8 +38,18 @@
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(macroexpand (car forms) (cdr forms)) (macroexpand (car forms) (cdr forms))
acc)) acc))
(else (else
;; A closure type's struct is emitted before the toplevel form that
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; first mentioned it, which is why the new forms are lifted off and
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; the structs slide underneath them
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let* ((processed (match-sex-form (car forms) acc))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(new (take-until processed acc)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(process-rec (cdr forms) (process-rec (cdr forms)
(match-sex-form (car forms) acc))))) (append new (flush-closure-structs!) acc))))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (take-until forms tail)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(if (eq? forms tail)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(list)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(cons (car forms) (take-until (cdr forms) tail))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (macroexpand macro-form rest-forms) (define (macroexpand macro-form rest-forms)
;; We want to replace macro with its expansion. The problem is, ;; We want to replace macro with its expansion. The problem is,
@@ -225,7 +236,7 @@
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(extract-fn-docstring (strip-fn-header-comments sex-fn-raw)))) (extract-fn-docstring (strip-fn-header-comments sex-fn-raw))))
(let* ((expanded (macro-expand sex-fn)) (let* ((expanded (macro-expand sex-fn))
(env (make-hash-table)) (env (make-hash-table))
(processed (lifted
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(walk-form (walk-form
expanded expanded
fn-walker fn-walker
@@ -233,25 +244,133 @@
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(set! (hash-table-ref env :fn-name) (sex-fn-name expanded)) (set! (hash-table-ref env :fn-name) (sex-fn-name expanded))
(set! (hash-table-ref env :lambda-counter) 0) (set! (hash-table-ref env :lambda-counter) 0)
(set! (hash-table-ref env :lambda-aux-code) (list)) (set! (hash-table-ref env :lambda-aux-code) (list))
env)))) (set! (hash-table-ref env :var-types)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(declared-types (sex-fn-arglist expanded)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
env)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(processed (rewrite-closure-calls-in-body lifted env)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(with-docstring doc processed (with-docstring doc processed
(append (hash-table-ref env :lambda-aux-code) acc))))) (append (hash-table-ref env :lambda-aux-code) acc)))))
(define (fn-walker form env) (define (declared-types arglist)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(if (eq? 'lambda (car form)) (let ((types (make-hash-table)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((lambda-name (make-lambda-name (hash-table-ref env :fn-name) (for-each (lambda (param)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(hash-table-ref env :lambda-counter)))) (when (and (pair? param) (pair? (cdr param)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(hash-table-set! types (first param) (second param))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
arglist)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
types))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (aux-name! env make)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((counter (hash-table-ref env :lambda-counter)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(set! (hash-table-ref env :lambda-counter) (+ counter 1))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(make (hash-table-ref env :fn-name) counter)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (add-aux-code! env forms)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(set! (hash-table-ref env :lambda-aux-code) (set! (hash-table-ref env :lambda-aux-code)
(append (lift-lambda lambda-name form) (append forms (hash-table-ref env :lambda-aux-code))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(hash-table-ref env :lambda-aux-code)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(set! (hash-table-ref env :lambda-counter) (define (fn-walker form env)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(+ (hash-table-ref env :lambda-counter) 1)) (let ((head (car form)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
lambda-name) (cond
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
form)) ((eq? 'lambda head)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((name (aux-name! env make-lambda-name)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(add-aux-code! env (lift-lambda name form))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
name))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; a type, not an expression -- becomes the struct for its signature
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((closure-type? form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(copy-form-source! form `(struct ,(register-closure-type! form form))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((eq? 'closure head)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((base (aux-name! env make-closure-name)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let-values (((construct forms) (lift-closure base form env)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(add-aux-code! env (fold match-sex-form (list) forms))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(copy-form-source! form `(,construct ,@(fourth form))))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; every binding site is written, so tracking the declarations is
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; enough to know a receiver's type without inference
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((and (eq? 'var head) (>= (length form) 3))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(hash-table-set! (hash-table-ref env :var-types) (second form) (third form))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(else form))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (rewrite-closure-calls-in-body fn-form env)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((header (fn-header-length fn-form)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(append (take fn-form header)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(map (lambda (form) (rewrite-closure-calls form env))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(drop fn-form header)))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (rewrite-closure-calls form env)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(if (not (list? form))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
form
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((type (and (pair? form) (receiver-closure-type (car form) env)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(rewrite (lambda (sub) (rewrite-closure-calls sub env))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(copy-form-source!
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
form
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(if type
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
`(,(register-closure-call! type form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
,(rewrite (car form))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
,@(map rewrite (cdr form)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(map rewrite form))))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; A closure type has two spellings: `(closure ...)' as written, and
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; `(struct ƛ...)' once resolved -- which is what a struct
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; field holds, since the type database is populated after resolution.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; Both name the same thing, so a receiver is recognised either way.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (as-closure-type type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(cond
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((closure-type? type) type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((and (list? type) (= 2 (length type)) (eq? 'struct (car type)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(hash-table-ref/default +closure-structs+ (second type) #f))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(else #f)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (receiver-closure-type expr env)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(as-closure-type (expression-type expr env)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; The type of an lvalue path, from known declarations -- a name, and
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; what can be reached from one by subscripting, dereferencing and
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; member access.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (expression-type expr env)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(cond
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((symbol? expr)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(hash-table-ref/default (hash-table-ref env :var-types) expr #f))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((not (and (list? expr) (>= (length expr) 2))) #f)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(else
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(case (car expr)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((¤) (let ((base (expression-type (second expr) env)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(and (list? base) (>= (length base) 2) (eq? '¤ (car base))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(second base))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((*) (and (= 2 (length expr))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((base (expression-type (second expr) env)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(and (list? base) (= 2 (length base)) (eq? '* (car base))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(second base)))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((dot-access) (member-path-type (expression-type (second expr) env)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(cddr expr)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((->) (let ((base (expression-type (second expr) env)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(and (list? base) (= 2 (length base)) (eq? '* (car base))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(member-path-type (second base) (cddr expr)))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(else #f)))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (member-path-type type fields)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(if (null? fields)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
type
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(member-path-type (field-type type (car fields)) (cdr fields))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (field-type type field)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((name (cond ((symbol? type) type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((and (list? type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(= 2 (length type))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(memq (car type) '(struct union)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(second type))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(else #f))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(and name
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let* ((fields (get-fields name))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(entry (and fields (assq field fields))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(and entry (second entry))))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (make-lambda-name enclosing-fn-name counter) (define (make-lambda-name enclosing-fn-name counter)
(string->symbol (string->symbol
(fmt #f "__lambda_" counter "_" enclosing-fn-name))) (fmt #f "λ" counter "_" enclosing-fn-name)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (lift-lambda name form) (define (lift-lambda name form)
(match form (match form
@@ -260,13 +379,255 @@
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(list))) (list)))
(else (sex-error form "malformed lambda" form)))) (else (sex-error form "malformed lambda" form))))
;;; Closures
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;;
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; A closure is a function pointer and an inline environment, so the
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; value owns its captures and nothing is allocated. The type
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; `(closure ((int)) int)' becomes one struct per signature, shared by
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; every closure with that signature. The captures live in `env' as a record
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

Re 347. The type gets what a fn header gets -- macro expansion and closure resolution, no walk.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) area)   ->  int (*fp)(int)

fe72a10.

Re 347. The type gets what a `fn` header gets -- macro expansion and closure resolution, no walk. ``` (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) area) -> int (*fp)(int) ``` fe72a10.
;;; only the lifted body knows the shape of, which is why `env' is
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; max_align_t rather than char -- it has to be aligned for whatever
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; ends up in it.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;;
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; The expression becomes three hoisted definitions -- the capture
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; struct, the lifted body, and a constructor -- and is replaced by a
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; call to the constructor, so the captures are evaluated as ordinary
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; arguments at the point the closure is written.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; How much of a closure is environment, in bytes. Counted in bytes
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; so a closure that fits where it was written will also fit
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; elsewhere. Captures are only by value, and never allocated on
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; heap. Anything that is more than 16 bytes should be stored as a
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; pointer, and memory management is entirely up to caller
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define +closure-env-bytes+ 16)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; +closure-env-bytes+ for maximum capacity, max-align-t for
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; effectiveness, hence union
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define +closure-env-type+ 'ƛenv)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (closure-env-declaration)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
`(union ,+closure-env-type+ ((align max-align-t)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(bytes (¤ char ,+closure-env-bytes+)))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define +closure-structs+ (make-hash-table))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define +closure-forwards+ (make-hash-table))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define *pending-closure-structs* (list))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (closure-type? form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(and (pair? form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(eq? 'closure (car form))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(= 3 (length form))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; A type spelling becomes an identifier deterministically, so two
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; translation units have the same signatures for the same closure
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; types: (* const char) -> p_const_char, (closure ((int)) int) ->
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; closure_int_int.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (mangle-type type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(cond
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((symbol? type) (mangle-word (symbol->string type)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((number? type) (number->string type))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((null? type) "void")
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((pair? type) (string-intersperse (map mangle-type (mangle-head type)) "_"))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(else (sex-error type "cannot mangle type" type))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (mangle-head type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

Re 348. A closure literal answers with its own type. The receiver is walked before the call helper is registered, so the struct is declared ahead of the signature naming it.

((closure ((x int)) int () (return x)) 5)  ->  5

fe72a10.

Re 348. A closure literal answers with its own type. The receiver is walked before the call helper is registered, so the struct is declared ahead of the signature naming it. ``` ((closure ((x int)) int () (return x)) 5) -> 5 ``` fe72a10.
(case (car type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((*) (cons 'p (cdr type)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((¤) (cons 'a (cdr type)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(else type)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (mangle-word word)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(list->string
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(map (lambda (c)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(if (or (char-alphabetic? c) (char-numeric? c)) c #\_))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(string->list word))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (aggregates-in type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(cond
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((not (list? type)) (list))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((and (= 2 (length type))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(memq (car type) '(struct union))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(symbol? (second type)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(list type))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(else (append-map aggregates-in type))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; Extract aggregate types from the closure's signature to forward
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; declare them before the closure, so they can be referenced in the
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; closure. Particularly useful for complex cases like fixed point
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; combinator, etc.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (forward-declare-aggregates! type src-form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(for-each
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(lambda (aggregate)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((name (second aggregate)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(unless (or (hash-table-exists? +closure-forwards+ name)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(get-tag-info name))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(hash-table-set! +closure-forwards+ name #t)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(set! *pending-closure-structs*
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(cons (copy-form-source! src-form aggregate)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
*pending-closure-structs*)))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(delete-duplicates (aggregates-in type))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (closure-struct-name type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; the glyph says `closure' already, so the tag is just the signature
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(string->symbol (string-append "ƛ"
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(mangle-type (second type))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
"_"
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(mangle-type (third type)))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; The code pointer takes the environment first; everything else is
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; the closure's own signature.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (closure-code-type type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
`(fn (((* void)) ,@(second type)) ,(third type)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; Emitted once per signature, before the toplevel form that first
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; needed it.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (register-closure-type! type src-form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((name (closure-struct-name type)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(unless (hash-table-exists? +closure-structs+ name)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(forward-declare-aggregates! type src-form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(hash-table-set! +closure-structs+ name type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((form (copy-form-source!
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
src-form
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
`(struct ,name ((code ,(closure-code-type type))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(env (union ,+closure-env-type+)))))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(register-aggregate! form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(set! *pending-closure-structs*
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(cons form *pending-closure-structs*))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
name))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; Every closure type in FORM becomes the struct for its signature,
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; registering it on the way. The walker does this for function bodies
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; and headers; globals come through here instead.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (resolve-closure-types form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(cond
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((closure-type? form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(copy-form-source! form `(struct ,(register-closure-type! form form))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((list? form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(copy-form-source! form (map resolve-closure-types form)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(else form)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define +closure-calls+ (make-hash-table))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; The helper a closure call is routed through: `(f 1)' becomes
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; `ƛint_int_call(f, 1)', which unpacks the receiver into
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; `ƛc.code(&ƛc.env, ƛa0)' inside. The receiver arrives as an argument,
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; so it is evaluated once: unpacked at the call site instead,
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; `([table (++ i)] 10)' would read
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; `table[++i].code(&table[++i].env, 10)' and bump `i' twice.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (register-closure-call! type src-form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let* ((closure (closure-struct-name type))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(helper (suffixed closure "_call"))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(returns (third type))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(params (map (lambda (arg index)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(list (string->symbol (fmt #f "ƛa" index))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(unwrap-type arg)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(second type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(iota (length (second type))))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(unless (hash-table-ref/default +closure-calls+ helper #f)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(hash-table-set! +closure-calls+ helper #t)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((call `((dot-access ƛc code)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(& (dot-access ƛc env))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
,@(map first params))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(set! *pending-closure-structs*
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(cons (copy-form-source!
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
src-form
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
`(fn ,helper ((ƛc (struct ,closure)) ,@params) ,returns
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
,(if (eq? 'void returns) call `(return ,call))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
*pending-closure-structs*))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
helper))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; An argument type is written wrapped: `(int)' in `((int) (float))'
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (unwrap-type type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(if (and (list? type) (= 1 (length type)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(car type)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
type))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (flush-closure-structs!)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((pending *pending-closure-structs*))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(set! *pending-closure-structs* (list))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
pending))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; Lowering
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (make-closure-name enclosing-fn-name counter)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(string->symbol (fmt #f "ƛ" counter "_" enclosing-fn-name)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (suffixed name suffix)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(string->symbol (string-append (symbol->string name) suffix)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; A capture is a plain name, whose type comes from the declarations
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; the walker has passed. `(name expr)' captures want the type of an
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; expression, which is inference, and wait for it.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (capture-binding capture form env)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(unless (symbol? capture)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(sex-error form "a closure capture must be a plain name for now" capture))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((type (hash-table-ref/default (hash-table-ref env :var-types) capture #f)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(unless type
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(sex-error form "closure captures an undeclared name" capture))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(list capture type)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (lift-closure base form env)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(match form
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(('closure arglist ret-type captures . body)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let* ((caps (map (lambda (c) (capture-binding c form env)) captures))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(record (suffixed base "_captures"))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(code (suffixed base "_code"))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(construct (suffixed base "_make"))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(type `(closure ,(map (lambda (p) (list (second p))) arglist)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
,ret-type))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(closure (register-closure-type! type form)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(values
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
construct
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(map (lambda (f) (copy-form-source! form f))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; C has no empty struct, and a closure over nothing needs
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; no record to point at
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(append
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(if (null? caps)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(list)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(list `(struct ,record ,caps)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(list
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
`(fn ,code ((ƛe (* void)) ,@arglist) ,ret-type
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
,@(if (null? caps)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(list)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
`((var ƛcaptures (* (struct ,record)) ƛe)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
,@(map (lambda (cap)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
`(var ,(first cap) ,(second cap)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(-> ƛcaptures ,(first cap))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
caps)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
,@body)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
`(fn ,construct ,caps (struct ,closure)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(var ƛc (struct ,closure))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
,@(if (null? caps)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(list)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
`((static-assert
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

Re 345.

(var e _ (¤ p 0))    p   : (* int)            ->  int e = p[0];
(var a _ (¤ pts 1))  pts : (¤ struct point 2) ->  struct point, was struct

2b73fcf.

Re 345. ``` (var e _ (¤ p 0)) p : (* int) -> int e = p[0]; (var a _ (¤ pts 1)) pts : (¤ struct point 2) -> struct point, was struct ``` 2b73fcf.
(<= (sizeof (struct ,record))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(sizeof (dot-access ƛc env)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
"closure captures do not fit the inline environment")))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(= (dot-access ƛc code) ,code)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
,@(if (null? caps)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(list)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
`((var ƛcaptures (* (struct ,record))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(cast (& (dot-access ƛc env)) (* (struct ,record))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
,@(map (lambda (cap)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
`(= (-> ƛcaptures ,(first cap)) ,(first cap)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
caps)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(return ƛc))))))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(else (sex-error form "malformed closure" form))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; Structs ;;; Structs
;;; Record the named structs, unions and enums in the type database ;;; Record the named structs, unions and enums in the type database
(define (process-struct sex-struct acc) (define (process-struct sex-struct acc)
(let-values (((doc form) (extract-aggregate-docstring sex-struct))) (let-values (((doc form) (extract-aggregate-docstring sex-struct)))
;; Resolve before registering: a field of closure type has to reach
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; the type database as the struct it becomes, or member access
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; through it finds nothing
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(let ((form (resolve-closure-types form)))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(register-aggregate! form) (register-aggregate! form)
(with-docstring doc form acc))) (with-docstring doc form acc))))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(define (register-aggregate! form) (define (register-aggregate! form)
(let* ((f (if (eq? (car form) 'pub) (cdr form) form)) (let* ((f (if (eq? (car form) 'pub) (cdr form) form))
Review

Re 343.

(&& a b) -> bool          (| a b) -> int
(<< l b) l : long -> long (>> c b) c : char -> int
(++ c)   c : char -> char

sextest wrote || escaped, which Sex does not read, so no test could have reached it. Fixed with it. e87463b.

Re 343. ``` (&& a b) -> bool (| a b) -> int (<< l b) l : long -> long (>> c b) c : char -> int (++ c) c : char -> char ``` sextest wrote `||` escaped, which Sex does not read, so no test could have reached it. Fixed with it. e87463b.
@@ -280,7 +641,9 @@
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
((enum) (add-enum name form)))))) ((enum) (add-enum name form))))))
(define (process-global-var sex-var acc) (define (process-global-var sex-var acc)
(cons sex-var acc)) ;; A global is not walked for lambdas, but its type still has to stop
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; saying `closure' before the writer sees it
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(cons (resolve-closure-types sex-var) acc))
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; Utils ;;; Utils
(define (non-empty-list? form) (define (non-empty-list? form)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.

View File

@@ -175,9 +175,10 @@ status, which is ours to pass on."
(semen-process raw-forms)))) (semen-process raw-forms))))
(define prelude (define prelude
(append
'((include inttypes.h) '((include inttypes.h)
(include stdbool.h) (include stdbool.h)
(include stddef.h) ; max_align_t, for closure environments
(typedef u8 uint8-t) (typedef u8 uint8-t)
(typedef i8 int8-t) (typedef i8 int8-t)
(typedef u16 uint16-t) (typedef u16 uint16-t)
@@ -185,7 +186,11 @@ status, which is ours to pass on."
(typedef u32 uint32-t) (typedef u32 uint32-t)
(typedef i32 int32-t) (typedef i32 int32-t)
(typedef u64 uint64-t) (typedef u64 uint64-t)
(typedef i64 int64-t))) (typedef i64 int64-t))
;; The closure environment is the part of the ABI, so include it in
;; every module
(list (closure-env-declaration))))
(define (main) (define (main)
(let* ((argv (command-line-arguments)) (let* ((argv (command-line-arguments))

View File

@@ -270,4 +270,59 @@ compiles."
"_Static_assert(sizeof(int) == 4, \"int is four bytes\")")) "_Static_assert(sizeof(int) == 4, \"int is four bytes\")"))
(test-assert "and not the header macro" (test-assert "and not the header macro"
(not (emits? (in-fn "(static-assert (== (sizeof int) 4) \"x\")") (not (emits? (in-fn "(static-assert (== (sizeof int) 4) \"x\")")
"static_assert("))))) "static_assert("))))
;; A closure is a code pointer beside its captures. The struct is
;; named from the signature, so separate translation units agree on
;; it, and calling one goes through `code' with `env' passed first.
;;
;; A closure struct, and the helper its calls go through, are each
;; emitted once per signature; the registries deciding that are
;; compile-time state like the type databases, and outlive a single
;; `sex->c' here. So every case below that looks for a *definition*
;; uses a signature of its own -- cases looking at a call site can
;; share one.
(test-group "closures"
(test-assert "the type becomes a struct named for its signature"
(emits? "(fn f ((c (closure ((int)) int))) int (return (c 1)))"
"struct ƛint_int"))
;; The environment is one shared union, declared in the prelude --
;; its layout is part of the ABI two units agree on, so it cannot
;; depend on what either file contains. `sex->c' has no prelude, so
;; what is visible here is the member
(test-assert "whose environment is the shared union"
(emits? "(fn f ((c (closure ((float)) int))) int (return (c 1.0)))"
"union ƛenv env;"))
;; The receiver goes through a helper rather than being written
;; out twice, so that `[table (++ i)]' evaluates its index once,
;; exactly as it would for an array of function pointers
(test-assert "a call passes the receiver to a helper"
(emits? "(fn f ((c (closure ((int)) int))) int (return (c 1)))"
"ƛint_int_call(c, 1)"))
(test-assert "and the helper is what dereferences it"
(emits? "(fn f ((c (closure ((long)) int))) int (return (c 1)))"
"ƛc.code(&ƛc.env, ƛa0)"))
(test-assert "a subscript receiver is evaluated once"
(emits? "(fn f ((t (¤ (closure ((int)) int) 4)) (i int)) int (return ((¤ t (++ i)) 1)))"
"ƛint_int_call(t[++i], 1)"))
(test-assert "so is a member receiver"
(emits? "(struct h ((cb (closure ((int)) int))))
(fn f ((s (struct h))) int (return ((. s cb) 1)))"
"ƛint_int_call(s.cb, 1)"))
(test-assert "a captured name is rebound in the lifted body"
(emits? "(fn f ((n int)) (closure ((char)) int) (return (closure ((x char)) int (n) (return n))))"
"int n = ƛcaptures->n;"))
(test-assert "captures are checked against the environment"
(emits? "(fn f ((n int)) (closure ((short)) int) (return (closure ((x short)) int (n) (return n))))"
"_Static_assert(sizeof(struct"))
;; A closure over nothing has no record to point at, and C has no
;; empty struct to declare for it
(test-assert "no captures means no capture record"
(not (emits? "(fn f () (closure () int) (return (closure () int () (return 7))))"
"_captures {")))
;; The receiver is written twice, so a name used as an argument
;; must not be mistaken for a call of its own
(test-assert "a closure passed as an argument stays a value"
(emits? "(fn g ((c (closure ((int)) int))) int (return 0))
(fn f ((c (closure ((int)) int))) int (return (g c)))"
"g(c)"))))

View File

@@ -10,14 +10,17 @@
# #
# It also checks what only a second translation unit can check: that an # It also checks what only a second translation unit can check: that an
# imported type reaches the type database, by expanding a macro that # imported type reaches the type database, by expanding a macro that
# reads the imported struct's fields. # reads the imported struct's fields; and that a closure type crossing
# the boundary works both ways -- one built in the module and called
# here, one built here and called there, through a code pointer that is
# static in the other object.
# #
# The public forms carry comments in their headers, which the reduction # The public forms carry comments in their headers, which the reduction
# to a prototype and to an extern both have to look past. # to a prototype and to an extern both have to look past.
SEXC ?= ../../sexc SEXC ?= ../../sexc
EXPECTED = hello, world\nhello, sex\n2 greetings\ntext times \ntext times \nmood 1 EXPECTED = hello, world\nhello, sex\n2 greetings\ntext times \ntext times \nmood 1\nclosure 15 21 201
check: check:
@$(SEXC) greet.sex -c -o greet.o @$(SEXC) greet.sex -c -o greet.o

View File

@@ -26,4 +26,11 @@
(printf "\n") (printf "\n")
(var m (enum mood) grumpy) (var m (enum mood) grumpy)
(printf "mood %d\n" m) (printf "mood %d\n" m)
(var add-10 (closure ((int)) int) (make-adder 10))
(printf "closure %d %d" (add-10 5) (apply-twice add-10 1))
(var base int 100)
(var here (closure ((int)) int)
(closure ((x int)) int (base) (return (+ base x))))
(printf " %d\n" (apply-twice here 1))
(return 0)) (return 0))

View File

@@ -35,6 +35,19 @@
(++ greet-count) (++ greet-count)
(printf "hello, %s\n" name)) (printf "hello, %s\n" name))
;;; A closure type crossing the boundary. Both units generate the
;;; struct for this signature independently, so they have to agree on
;;; its tag and its layout, or the value is passed wrong and nothing
;;; says so.
(pub fn make-adder ((n int)) (closure ((int)) int)
(return (closure ((b int)) int (n)
(return (+ n b)))))
;;; The other direction: a closure built by the importer, whose code
;;; pointer is static in *its* object, called from here
(pub fn apply-twice ((f (closure ((int)) int)) (x int)) int
(return (f (f x))))
;;; Not `pub': invisible to importers, and static in the generated C. ;;; Not `pub': invisible to importers, and static in the generated C.
(fn unused-helper () void (fn unused-helper () void
(printf "private\n")) (printf "private\n"))

View File

@@ -0,0 +1,80 @@
(input)
(output "Adders: 15 25"
"Two captures: 47"
"No captures: 7"
"Through a parameter: 110"
"From an array: 1 2 3"
"Index evaluated once: 21 i 1"
"Through a struct member: 8"
"Nested: 33")
(return 0)
;;; A closure is a code pointer beside its captures, so what this
;;; checks is that the captures survive the lifting -- that two
;;; closures of one shape keep their own environments, that a closure
;;; outlives the call that built it, and that calling one through a
;;; parameter, an array element or a struct member resolves the same
;;; way as through a local.
;;;
;;; A receiver is also an ordinary expression: `[table (++ i)]' has to
;;; evaluate its index exactly once, the way it would for an array of
;;; function pointers.
(include stdio.h)
(fn make-adder ((n int)) (closure ((int)) int)
(return (closure ((b int)) int (n)
(return (+ n b)))))
(fn make-affine ((k int) (b int)) (closure ((int)) int)
(return (closure ((x int)) int (k b)
(return (+ (* k x) b)))))
(fn make-const-7 () (closure () int)
(return (closure () int ()
(return 7))))
;;; A closure arriving as a parameter: its type is written, so the call
;;; resolves without knowing where it came from
(fn apply-twice ((f (closure ((int)) int)) (x int)) int
(return (f (f x))))
(struct handlers ((on-tick (closure ((int)) int))))
(pub fn main () int
(var add-10 (closure ((int)) int) (make-adder 10))
(var add-20 (closure ((int)) int) (make-adder 20))
(printf "Adders: %d %d\n" (add-10 5) (add-20 5))
(var affine (closure ((int)) int) (make-affine 5 2))
(printf "Two captures: %d\n" (affine 9))
(var seven (closure () int) (make-const-7))
(printf "No captures: %d\n" (seven))
(printf "Through a parameter: %d\n" (apply-twice (make-adder 50) 10))
(var table (¤ (closure ((int)) int) 3))
(var i int 0)
(for (= i 0) (< i 3) (++ i)
(= (¤ table i) (make-adder i)))
(printf "From an array: %d %d %d\n"
((¤ table 0) 1) ((¤ table 1) 1) ((¤ table 2) 1))
;; the index must be evaluated once, so `i' ends at 1 and not 2 --
;; read in a separate statement, since reading and bumping it in one
;; printf would be unsequenced whatever the closure did
(= i 0)
(var once int ([table (++ i)] 20))
(printf "Index evaluated once: %d i %d\n" once i)
(var h (struct handlers) #((struct handlers) : .on-tick (make-adder 5)))
(printf "Through a struct member: %d\n" ((. h on-tick) 3))
;; a closure built inside a closure, capturing that one's capture
(var outer (closure ((int)) int)
(closure ((x int)) int ()
(var inner (closure ((int)) int) (make-adder x))
(return (inner 3))))
(printf "Nested: %d\n" (outer 30))
(return 0))

View File

@@ -0,0 +1,55 @@
(input)
(output "direct: 120"
"fac: 120 3628800"
"fib: 55 6765")
(return 0)
;;; A fixed point built out of closures, which is the hardest thing to
;;; ask of them: recursion with no recursive function anywhere, only
;;; self-application.
;;;
;;; Self-application needs `x x' and so a recursive type, which is
;;; spelled here by routing it through a named struct whose field is a
;;; closure whose own signature mentions that struct. The generated
;;; closure struct is written before `struct rec' is, so this only
;;; compiles because a forward declaration is emitted ahead of both.
;;;
;;; Note what `fix' captures: a *pointer* to the knot, not the knot. A
;;; closure is a code pointer beside N bytes of environment, so
;;; capturing one by value would need N >= 8 + N. No budget makes that
;;; true, and the static assertion says so rather than letting it
;;; corrupt anything.
(include stdio.h)
(struct rec ((f (closure (((* (struct rec))) (int)) int))))
;;; Takes a step that expects itself, returns an ordinary closure with
;;; the self-application hidden inside
(fn fix ((step (* (struct rec)))) (closure ((int)) int)
(return (closure ((n int)) int (step)
(return ((-> step f) step n)))))
(pub fn main () int
(var fac-knot (struct rec))
(= (. fac-knot f)
(closure ((self (* (struct rec))) (n int)) int ()
(if (<= n 1) (return 1))
(return (* n ((-> self f) self (- n 1))))))
;; the knot applied to itself directly, without fix
(printf "direct: %d\n" ((. fac-knot f) (& fac-knot) 5))
(var fib-knot (struct rec))
(= (. fib-knot f)
(closure ((self (* (struct rec))) (n int)) int ()
(if (< n 2) (return n))
(return (+ ((-> self f) self (- n 1))
((-> self f) self (- n 2))))))
;; one combinator, two different recursions
(var fac (closure ((int)) int) (fix (& fac-knot)))
(var fib (closure ((int)) int) (fix (& fib-knot)))
(printf "fac: %d %d\n" (fac 5) (fac 10))
(printf "fib: %d %d\n" (fib 10) (fib 20))
(return 0))