type-inference #39

Open
alex-eg wants to merge 17 commits from type-inference into main
5 changed files with 97 additions and 93 deletions
Showing only changes of commit a860da6d7e - Show all commits

View File

@@ -381,11 +381,13 @@ forms, and what remains."
;; are not part of it: ((* const char)), (int)
(walk-type (maybe-unwrap-type arg))))
;;; A parameter reaches fmt-c as `(type name)' and nothing else: it
;;; reads the name out with `cadr', so a nameless one is the type and
;;; an explicit #f. Handing it the bare type instead made it read the
;;; type's own second word as the name -- `(* const char)' lost its
;;; star -- and a one-word type had no second word to read at all.
;;; fmt-c reads a parameter as `(type name)', taking the name with
;;; `cadr'. A nameless one is the type and an explicit #f:
;;;
;;; (* const char) -> const char the star read as the name
;;; ((* const char) #f) -> const char *
;;; (int) -> (cadr) error
;;; (int #f) -> int
(define (walk-arglist form)
;; E.g.:
;; ((float) (int) (const char) (* const char) (¤ (* const struct res) 32))

View File

@@ -509,9 +509,9 @@
((eq? a b) #t)
((unknown-type? a) #t)
((unknown-type? b) #t)
;; Whichever side is free takes the binding, so that a rigid
;; variable is solved *to* rather than solved, in either order.
;; Both rigid and distinct is the mismatch `eq?' above let through.
;; Whichever side is free takes the binding: `(unify a r)' and
;; `(unify r a)' both leave `a' bound to `r'. Two rigid and
;; distinct is the mismatch `eq?' above let through.
((and (tvar? a) (not (tvar-rigid? a))) (bind-tvar! a b form))
((and (tvar? b) (not (tvar-rigid? b))) (bind-tvar! b a form))
((or (tvar? a) (tvar? b)) (type-mismatch a b form))

131
semen.scm
View File

@@ -299,12 +299,15 @@
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
;;;
;;; `(do (var c int 9) ...)' declares a `c' that ends with the block, so
;;; a closure-typed `c' outside it is still a closure after it. Every
;;; form whose body C brackets opens a frame; innermost 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.
;;; form whose body C brackets opens a frame; innermost 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.
;;;
;;; One frame per form is enough, rather than one per arm: a `case' label
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 v double 3.75)
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; (while (< v 0) (var v char 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.
;;; (var m _ (+ v 1)) ; double, not char
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
;;; One frame per form, not one per arm: a `case' label opens no scope
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 (declare-name! env name type)
(hash-table-set! (car (hash-table-ref env :scopes)) name type))
@@ -383,10 +386,11 @@
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
((var)
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.
;; the initializer is walked before the name it binds is in
;; scope; the type is resolved rather than walked, a `fn' type's
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 ((c int)) int)' with a closure named `c' in scope would
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 the parameter as a call of 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.
;; scope; the type is resolved rather than walked, a parameter
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 being shaped like a 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.
;;
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 (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.
;; (var fp (fn ((c int)) int) ...) ; int (*fp)(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.
(let* ((prefix (if (>= (length form) 3)
(append (take form 2)
(list (resolve-closure-types
@@ -427,9 +431,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.
(else
(let ((closure (receiver-closure-type (car form) env)))
(if closure
;; the receiver is walked first: a closure written where 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.
;; is called registers its struct on the way, and the 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.
;; helper's signature mentions that 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.
;; the receiver is walked first: `((closure ((x 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.
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.
;; () ...) 5)' registers `struct ƛint_int' on the way, 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 call helper's signature names 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.
(let ((receiver (walk-statement (car form) env)))
(copy-form-source!
form
@@ -530,10 +534,12 @@
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 (pair (cdr params) (- remaining 1)
(cons (unwrap-type (car params)) acc))))))
;;; A `fn' header has its macros expanded and its closure 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.
;;; resolved without being walked; a `var' type is the same thing 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.
;;; same position, and gets the same two. A macro standing in for a 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.
;;; may still ask `(type-of x)' while it does so.
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 a `fn' header gets, a `var' type gets -- macro expansion 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.
;;; closure resolution, no walk:
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
;;; (defmacro (ty) 'int) (var x (ty) 0) -> int x = 0;
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
;;; and the macro may ask `(type-of x)' while it stands in for a 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 (expand-type type env)
(let ((expanded
(parameterize ((current-type-of
@@ -594,8 +600,8 @@
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
(and (symbol? (car expr)) (get-return-type (car expr))))
(else
(case (car expr)
;; subscripting an array gives its element type, and a pointer
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; subscripts the same 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.
;; (¤ pts 1), pts : (¤ struct point 2) -> (struct 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.
;; (¤ p 1), p : (* 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.
((¤) (let ((base (expression-type (second expr) env)))
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.
(or (array-element-type base) (pointer-target base))))
;; unary `&' takes an address; with two operands it is bitwise and
@@ -613,9 +619,8 @@
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
(cddr expr)))
((cast) (and (= 3 (length expr)) (third expr)))
((sizeof) 'size-t)
;; a closure literal is its own type: the first three elements
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; like calling one through a 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.
;; `(closure ((x int)) int () ...)' is a `(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.
;; so `((closure ((x int)) int () (return x)) 5)' is a 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.
((closure) (and (closure-expression? expr)
`(closure ,(arglist-types (second expr)) ,(third expr))))
;; `c-and' and `c-or' are the names from before `&&' and `||'
@@ -623,11 +628,11 @@
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
((+ - / %) (arithmetic-type expr env))
;; the bitwise operators join like the arithmetic ones
((^ |\||) (arithmetic-type expr env))
;; a shift does not join: the result is the promoted left operand,
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 the right one says only how far
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 shift is the promoted left operand, not a join:
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; (<< l b), l : long -> long; (>> c b), c : char -> 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.
((<< >>) (promoted-type (expression-type (second expr) env)))
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.
;; ...and an increment is not a join either -- it is the operand,
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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), c : char -> char
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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-type (second expr) env))
;; otherwise a call: a closure answers with its own return type,
;; anything else with what its signature says
@@ -661,37 +666,36 @@
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
(cond
((or (ptr-type? l) (array-type? l)) (decayed left l))
((or (ptr-type? r) (array-type? r)) (decayed right r))
;; one type on both sides needs no ranking, which is the only 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.
;; a name we never parsed a declaration for joins at all
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; one type on both sides needs no ranking:
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; (+ n n), n : size-t -> size-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.
((and (prim-type? l) (prim-type? r) (equal? (prim-name l) (prim-name r)))
(promoted left l))
((or (unrankable? l) (unrankable? r)) '?)
((< (conversion-rank l) (conversion-rank r)) (promoted right r))
((> (conversion-rank l) (conversion-rank r)) (promoted left l))
;; at equal rank C takes the unsigned one, whichever side it 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.
;; written 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.
;; (+ i u) and (+ u i) are both unsigned 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.
((unsigned-type? r) (promoted right r))
(else (promoted left l)))))))
;;; A name we never parsed a declaration for -- `size-t', `GLuint' --
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; has no rank we can know, so a join that would have to compare one
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; answers `?' instead of taking whichever operand came 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.
;;; `resolve-wildcard' turns that into "write it out", which is the only
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; honest thing to say about 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.
;;; `size-t', `GLuint': no declaration parsed, so no rank to compare.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
;;; (var m _ (+ 1 n)) n : size-t -> type of this is unknown
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 m size-t (+ 1 n)) -> size_t m = 1 + n;
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 (unrankable? type)
(and (prim-type? type) (not (c-primitive? type))))
(define (unsigned-type? type)
(and (prim-type? type) (memq 'unsigned (prim-name type)) #t))
;;; Anything narrower than `int' is promoted to one before 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.
;;; arithmetic happens, so two `char's join as `int' and not as `char'.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; Operands of the same type reach here too, which is the whole 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.
;;; `(+ c c)' is where the promotion is invisible and the truncation 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.
;;; not. `unsigned' alone is `unsigned int' and stays as 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.
;;; An array is a pointer to its first element the moment it is 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.
;;; operand, so `(+ a 1)' is a `(* int)' and not the `(¤ int 4)' 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.
;;; `a' was declared as -- which is not a type an initializer can have.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; Narrower than `int' promotes to one:
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
;;; (+ c c) c : char 100 -> int 200, not char -56
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; (+ h h) h : short 30000 -> int 60000, not short -5536
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; (+ u u) u : unsigned -> unsigned -- `unsigned' is unsigned 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.
;;; An array operand is a pointer to its first element:
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
;;; (var p _ (+ a 1)) a : (¤ int 4) -> int * p = a + 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.
;;; not int p[4] = a + 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.
(define (decayed written type)
Review

Re 344. decay has its caller.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))   ->  int * p = a + 1;

e87463b.

Re 344. `decay` has its caller. ``` (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) -> int * p = a + 1; ``` e87463b.
(if (array-type? type) (unparse-type (decay type)) written))
@@ -776,11 +780,11 @@
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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)
;;; +closure-env-bytes+ for maximum capacity, and an alignment wide
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 for anything that fits in them, hence union. `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.
;;; would say that in one word, but it is C11 and the target is C99, so
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; the widest built-ins say it instead: a union is aligned for 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.
;;; strictest of its members.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 capacity, the widest built-ins 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.
;;; alignment, hence union -- a union takes the strictest alignment of
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; its members. `max_align_t' would say the second in one 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.
;;; sexc hello-world.sex -- -std=c99 unknown type name '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.
(define +closure-env-type+ 'ƛenv)
(define (closure-env-declaration)
@@ -854,15 +858,14 @@
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
*pending-closure-structs*)))))
(delete-duplicates (aggregates-in type))))
;;; Where one argument ends and the next begins has to survive 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.
;;; flattening, or `((long long))' and `((long) (long))' mangle alike 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 second signature silently reuses the first one's struct. Words
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; within an argument keep the single separator; the arguments take 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.
;;; doubled one.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; The words inside an argument take the single separator, 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.
;;; arguments a doubled one:
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 proof against a type name that mangles to a trailing `_' of its
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; own -- for that the arguments would have to carry their lengths, 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 name in the C is worth more than the last of the ambiguity.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 ((long long)) int) -> ƛlong_long_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 ((long) (long)) int) -> ƛlong__long_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.
;;;
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 word whose first character mangles to `_' still aliases 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.
;;; doubled separator: `((a -b))' and `((a) (b))' are both `a__b'.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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-arglist args)
(if (null? args)
"void"
@@ -1040,8 +1043,8 @@
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 (capture-name capture)))
(unless (symbol? name)
(sex-error form "a closure capture needs a name" capture))
;; the same lookup either way: a capture that borrows a name can
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; borrow a global's or a function's, not only a local's
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; the same lookup either way, so `(closure ((x int)) int (scale)
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; ...)' borrows a global's `scale' as readily as a local's
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 (expression-type (capture-argument capture) env)))
(unless type
(sex-error form "cannot infer what is captured as" name))
@@ -1128,23 +1131,21 @@
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
((union) (add-union name form))
((enum) (add-enum name form))))))
;;; A toplevel form has no function around it and so no scope chain. 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.
;;; name in a global's initializer is another global's or a function's,
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; which `get-name-type' answers without one.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 function around a toplevel form, so no scope chain: what 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.
;;; global's initializer names comes from `get-name-type' alone.
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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-toplevel-env)
(let ((env (make-hash-table)))
(set! (hash-table-ref env :scopes) (list))
env))
(define (process-global-var 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.
;; saying `closure' before the writer sees it, and a `_' still has to
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; be written out: the writer has no spelling for one 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.
;; A global is not walked for lambdas, but the writer spells neither
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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 346. Solved from get-name-type alone, so a global names only what is declared above it.

(var n _ 1)     ->  static int n = 1;
(var s _ "hi")  ->  static const char * s = "hi";

e87463b.

Re 346. Solved from `get-name-type` alone, so a global names only what is declared above it. ``` (var n _ 1) -> static int n = 1; (var s _ "hi") -> static const char * s = "hi"; ``` e87463b.
;; `closure' nor `_': `(var n _ 1)' has to reach it as `int n = 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.
(let* ((resolved (resolve-closure-types sex-var))
(qualifier (and (memq (car resolved) '(pub extern)) (car resolved)))
(core (if qualifier (cdr resolved) resolved))
;; `extern' declares without initializing, so there is 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.
;; for a `_' to be worked out from
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; `(extern var n int)' has no initializer to work a `_' out
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;; from
Review

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source.

With n a size-t (an unparsed name, rank 1, same as int):

int m1 = 1 + n;
size_t m2 = n + 1;

cc accepts both. C types 1 + n as size_t, and the int declaration narrows. The same tie makes (+ i u) an int and (+ u i) an unsigned int. char + char is declared char.

size-t never reaches the long rank because it is not a typedef Sex has parsed, so the strlen example's (+ 1 n) lands here.

When the ranks tie this keeps the left operand, so the declared type depends on the order of the source. With `n` a `size-t` (an unparsed name, rank 1, same as `int`): ```c int m1 = 1 + n; size_t m2 = n + 1; ``` `cc` accepts both. C types `1 + n` as `size_t`, and the `int` declaration narrows. The same tie makes `(+ i u)` an `int` and `(+ u i)` an `unsigned int`. `char + char` is declared `char`. `size-t` never reaches the `long` rank because it is not a typedef Sex has parsed, so the `strlen` example's `(+ 1 n)` lands here.
Review

The forms that reach this walk are &&, ||, |, &, <<, >>, ++. c-and and c-or are the names from before those spellings. The writer already emits a && b from (&& a b).

(var ok _ (&& a b)) and (var x _ (<< a b)) and (var x _ (++ a)) all stop with cannot infer the type of.

The forms that reach this walk are `&&`, `||`, `|`, `&`, `<<`, `>>`, `++`. `c-and` and `c-or` are the names from before those spellings. The writer already emits `a && b` from `(&& a b)`. `(var ok _ (&& a b))` and `(var x _ (<< a b))` and `(var x _ (++ a))` all stop with `cannot infer the type of`.
Review

An array operand is returned as the array. decay in infer.scm is the conversion this comment describes, and nothing in the walk calls it.

(var a (¤ int 4) #(1 2 3 4))
(var p _ (+ a 1))

emits int p[4] = a + 1. cc: invalid initializer.

An array operand is returned as the array. `decay` in `infer.scm` is the conversion this comment describes, and nothing in the walk calls it. ```sex (var a (¤ int 4) #(1 2 3 4)) (var p _ (+ a 1)) ``` emits `int p[4] = a + 1`. `cc`: `invalid initializer`.
Review

A subscript types only when the base's surface form is already (¤ ...). An (* int) is not, so

(fn f ((p (* int))) int
  (var e _ (¤ p 0))
  (return e))

stops with cannot infer the type of. This is the other use named on decay.

A subscript types only when the base's surface form is already `(¤ ...)`. An `(* int)` is not, so ```sex (fn f ((p (* int))) int (var e _ (¤ p 0)) (return e)) ``` stops with `cannot infer the type of`. This is the other use named on `decay`.
Review

resolve-closure-types runs here and resolve-wildcard does not. (var n _ 1) at toplevel emits static _ n = 1. cc: unknown type name '_'. The same form inside a function becomes int n = 1.

`resolve-closure-types` runs here and `resolve-wildcard` does not. `(var n _ 1)` at toplevel emits `static _ n = 1`. `cc`: `unknown type name '_'`. The same form inside a function becomes `int n = 1`.
Review

walk-parts walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a fn type.

(var c (closure ((int)) int) (make-adder 1))
(var fp (fn ((c int)) int) (lambda ((c int)) int (return c)))

-m shows (var fp (fn ((ƛint_int_call c int)) int) ...), and the C is int (*fp)(c int). With no closure named c, the same declaration emits int (*fp)(int).

`walk-parts` walks the type as well as the initializer. A list whose head is an in-scope closure is rewritten as a closure call, including a parameter name inside a `fn` type. ```sex (var c (closure ((int)) int) (make-adder 1)) (var fp (fn ((c int)) int) (lambda ((c int)) int (return c))) ``` `-m` shows `(var fp (fn ((ƛint_int_call c int)) int) ...)`, and the C is `int (*fp)(c int)`. With no closure named `c`, the same declaration emits `int (*fp)(int)`.
Review

The callee is typed before it is walked, so a closure literal has no type yet and falls through to convert-arguments. After the walk the form is a call of the constructor:

return ƛ0_f_make()(5);

cc: called object is not a function or function pointer. ((lambda ((x int)) int (return x)) 5) works, because the lifted function is registered before the call is typed. ((make-adder 20) 22) works, because the callee is already a call with a closure return type.

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
(core (if (eq? 'extern qualifier)
core
(resolve-wildcard core (make-toplevel-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.

View File

@@ -87,10 +87,9 @@
;; `process' returns one record; `process-input-port' is named from
;; the child's side, so it is the port we write to.
;;
;; Sex has no symbol escaping -- `|' is an operator there, not a
;; quote -- so the forms go out the way they were written. Left to
;; escape, `||' would leave here as `|\|\||' and reach sexc as a
;; different symbol.
;; Sex reads no symbol escaping -- `|' is an operator there. Left
;; on, `(|| a b)' leaves here as `(|\|\|| a b)' and reaches sexc
;; as a different symbol.
(let* ((proc (process compiler (append (list "-o" compiled-file) flags)))
(sexc-stdin (process-input-port proc)))
(symbol-escape #f)

View File

@@ -240,14 +240,14 @@
;;; The shape of a written type
;;;
;;; Three places have to tell a type from something that merely
;;; contains one: an arglist entry is either `(name type)' or a bare
;;; type, and an array's last element is either a bound or the last
;;; word of its element type. They used to answer it separately, and
;;; disagreed.
;;; Where a type ends, asked by an arglist and by an array bound:
;;;
;;; (f1 float) a name and a type (unsigned int) a type
;;; (¤ int 4) four of int (¤ const t) unsized, of const t
;;; (¤ mytype N) N of mytype (¤ * size-t) unsized, of (* size-t)
;;; A qualifier can never end a type, which is what tells `(¤ const t)'
;;; -- an unsized array of `t' -- from `(¤ int 4)'.
;;; A qualifier cannot end a type: `(¤ const t)' is unsized, `(¤ int 4)'
;;; is four of int.
(define +c-qualifiers+ '(const volatile restrict _Atomic))
(define +c-specifiers+
@@ -271,20 +271,22 @@
(pair? (cdr arg)) ; 1 element args are always type
(not (type-head? arg))))
;;; Is NAME a typedef, as opposed to a `define'd constant? Both live in
;;; the same table, and only the first is part of a type.
;;; A typedef and a `define' share +type-db+; only the typedef is part
;;; of a type:
;;;
;;; (typedef small int) -> (¤ small N) is N of small
;;; (define CAP 4) -> (¤ int CAP) is CAP of int
(define (typedef-name? name)
(let ((info (and (symbol? name) (get-type-info name))))
(and info (memq (car info) '(typedef struct union enum)) #t)))
;;; `(¤ int N)' is N of int
;;; `(¤ unsigned int)' is an unsized array of unsigned int
;;; The last element is a bound only where what precedes it already
;;; spells a whole type -- a specifier, a tag after its keyword, or a
;;; typedef we have seen declared:
;;;
;;; The last element is a bound only if what precedes it is already a
;;; complete type, so `(¤ const mytype)' and `(¤ * size-t)' end in the
;;; last word of their element type and not in a bound. A type is
;;; complete when it ends in a specifier, in a tag following its
;;; keyword, or in a typedef we have seen declared.
;;; (¤ int 4) four of int (¤ unsigned int) unsized
;;; (¤ mytype CAP) CAP of mytype (¤ struct point) unsized
;;; (¤ const mytype) unsized (¤ * size-t) unsized
;;;
;;; TYPE is the whole `(¤ ...)' form.
(define (array-bound? type)