type-inference #39

Open
alex-eg wants to merge 17 commits from type-inference into main
2 changed files with 50 additions and 7 deletions
Showing only changes of commit 578feb6b73 - Show all commits

View File

@@ -295,8 +295,13 @@
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function is registered before the call is typed. `((make-adder 20) 22)` works, because the callee is already a call with a closure return type.
;;; The scope chain
;;;
;;; `(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. `do' 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.
;;; `for' each open 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.
;;; a closure-typed `c' outside it is still a closure after it. Every
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

The callee is typed before it is walked, so a closure literal has no type yet and falls through to `convert-arguments`. After the walk the form is a call of the constructor: ```c return ƛ0_f_make()(5); ``` `cc`: `called object is not a function or function pointer`. `((lambda ((x int)) int (return x)) 5)` works, because the lifted function 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.
(define (declare-name! env name type)
(hash-table-set! (car (hash-table-ref env :scopes)) name type))
@@ -351,7 +356,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.
(cons walk-embed-result (walk-body expansion env)))))
(else
(case (car form)
((do for) (with-scope env (lambda () (walk-parts form env))))
Review

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return ƛ0_f_make()(5);

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

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

View File

@@ -6,8 +6,10 @@
"arrays: 30"
"loop: 0 1 2"
"shadowed: 9 then 42"
"still an int: 200"
"partial: 1 2.5"
"joined: 43.5 84 49 1"
"promoted: 200 60000 3705032704"
"from elements: 4 9 0")
(return 0)
@@ -55,11 +57,24 @@
(printf " %d" i))
(printf "\n")
;; a block's declarations end with it
;; a block's declarations end with it, and so do the declarations of
;; everything else C brackets -- a `while' body is a block with no
;; `do' written around it
(do (var n _ 9)
(printf "shadowed: %d then " n))
(printf "%d\n" n)
(var wide int 200)
(while false (var wide char 1) (printf "%d" wide))
(if false (do (var wide char 1) (printf "%d" wide)))
;; a statement before the declaration: a label may not be followed by
;; one until C23
(switch a (case 1 (printf "") (var wide char 1) (printf "%d" wide) (break)))
;; a copy, not a sum: an arithmetic result would be promoted to `int'
;; whatever leaked, and say nothing
(var copy _ wide)
(printf "still an int: %d\n" copy)
;; a wildcard inside a written type: only it is solved
(var pp2 (* _) (& p))
(printf "partial: %d %g\n" (-> pp2 x) (-> pp2 y))
@@ -74,6 +89,17 @@
(var single _ (+ g g))
(printf "joined: %g %d %ld %g\n" mixed same wider single)
;; ...including the promotions, which two operands of one narrow type
;; are exactly where they show: `char' + `char' is an `int'
(var c1 char 100)
(var c2 char 100)
(var h1 short 30000)
(var narrow _ (+ c1 c2))
(var narrower _ (+ h1 h1))
(var kept (unsigned int) 4000000000)
(var unpromoted _ (+ kept kept))
(printf "promoted: %d %d %u\n" narrow narrower unpromoted)
;; a brace initializer has no type of its own, but its elements solve
;; the hole in the array type around it -- and the length stays as
;; written, whether or not every slot is initialized