Skip to content

Commit 4394ae4

Browse files
shirokstylewarning
authored andcommitted
Derive specialized lisp types for transparent type
If a Coalton type is transparent type and specialized to a concrete type, propagate the specialization when deriving lisp-type. This enables underlying Lisp compiler to do more optimization. Example: Suppose you have ``` (repr :transparent) (define-type (Foo :t) (Foo (LispArray :t))) ``` Then, if you compute Lisp type of `(Foo Single-Float)`, it returns `(simple-array single-float (*))`.
1 parent 2a2b0bf commit 4394ae4

File tree

3 files changed

+124
-2
lines changed

3 files changed

+124
-2
lines changed

coalton.asd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@
240240
(:file "runtime-tests")
241241
(:module "typechecker"
242242
:serial t
243-
:components ((:file "map-tests")))
243+
:components ((:file "map-tests")
244+
(:file "lisp-type-tests")))
244245
(:file "environment-persist-tests")
245246
(:file "slice-tests")
246247
(:file "float-tests")

src/typechecker/lisp-type.lisp

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,13 @@ USE-FUNCTION-ENTRIES specifies whether to emit FUNCTION-ENTRY for functions, emi
102102
(if (typep to 'tyvar)
103103
`(cl:simple-array cl:* (cl:*))
104104
`(cl:simple-array ,(lisp-type to env) (cl:*))))
105-
105+
106+
;; When FROM is a transparent type, and we got a specialized type,
107+
;; we propagate parameterization to the inner type.
108+
((and (not (typep to 'tyvar))
109+
(try-recurse-transparent-type from to env)))
110+
111+
106112
;; Otherwise we fall back.
107113
(t
108114
(lisp-type (tapp-from ty) env)))))
@@ -124,3 +130,51 @@ USE-FUNCTION-ENTRIES specifies whether to emit FUNCTION-ENTRY for functions, emi
124130
(:method ((ty qualified-ty) env)
125131
(lisp-type (qualified-ty-type ty) env)))
126132

133+
134+
(defun try-recurse-transparent-type (from parameter env)
135+
"Called when taking a lisp-type of a parameterized type, where a
136+
concrete type is given to the parameter. For example, a type `(Foo
137+
:t)` is defined, and we try to take a lisp-type of `(Foo UFix)`. The
138+
`FROM` argument gets the type `Foo` and the `parameter` argument gets
139+
the type `UFix`.
140+
141+
There is a special opportunity of optimization when `Foo` is defined
142+
as a transparent type, e.g. `(repr :transparent) (define-type (Foo
143+
:t) (Content (Lisparray :t)))`. In that case, `(Foo UFix)` can have a
144+
Lisp type `(cl:simple-array cl:fixnum)`, which allows Lisp compiler to
145+
optimize further. We check the conditions and returns a specialized
146+
Lisp type if possible.
147+
148+
If we can't get a specialized Lisp type, this returns nil, and let the
149+
fallback branch take care of it.
150+
"
151+
(labels ((transparent-type? (from)
152+
(alexandria:when-let (entry (lookup-type env from :no-error t))
153+
(eq (type-entry-explicit-repr entry) ':transparent)))
154+
(reveal-underlying-type (from)
155+
"If `from` type satisfies the optimizable condition, returns two
156+
values: the 'inner' type (wrappee type) and the 'outer' type (wrapper
157+
type)."
158+
(let ((v (lookup-value-type env from :no-error t)))
159+
(when (typep v 'ty-scheme)
160+
(let ((qt (qualified-ty-type (ty-scheme-type v))))
161+
;; In transparent types, we have this in QT.
162+
;; (Arrow <innter-type>) -> <outer-type>
163+
(when (function-type-p qt)
164+
(values (function-type-from qt)
165+
(function-type-to qt))))))))
166+
(and (transparent-type? from)
167+
(multiple-value-bind (inner outer) (reveal-underlying-type from)
168+
(cond ((and (typep inner 'tycon)
169+
(typep outer 'tycon))
170+
(lisp-type inner env))
171+
((and (typep inner 'tapp)
172+
(typep outer 'tapp)
173+
(typep (tapp-to inner) 'tgen)
174+
(eq (tapp-to inner) (tapp-to outer)))
175+
;; Substitute inner type's type variable with the
176+
;; concrete type
177+
(lisp-type (make-tapp :from (tapp-from inner)
178+
:to parameter)
179+
env))
180+
(t nil))))))
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
(in-package #:coalton-native-tests)
2+
3+
(coalton-toplevel
4+
(repr :transparent)
5+
(define-type (TransparentTypeTest :t)
6+
(TransparentTypeTest (coalton-library/lisparray:LispArray :t)))
7+
8+
(declare complex-type-fn ((Complex :t) -> (Complex :t)))
9+
(define (complex-type-fn x) x)
10+
11+
(declare complex-type-fn-1 ((Complex Double-Float) -> (Complex Double-Float)))
12+
(define (complex-type-fn-1 x) x)
13+
14+
(declare lisp-array-fn ((coalton-library/lisparray:LispArray :t) -> :t))
15+
(define (lisp-array-fn x)
16+
(coalton-library/lisparray:aref x 0))
17+
18+
(declare lisp-array-fn-1 ((coalton-library/lisparray:LispArray IFix) -> IFix))
19+
(define (lisp-array-fn-1 x)
20+
(coalton-library/lisparray:aref x 0))
21+
22+
(declare transparent-type-fn ((TransparentTypeTest :t) -> :t))
23+
(define (transparent-type-fn (TransparentTypeTest x))
24+
(coalton-library/lisparray:aref x 0))
25+
26+
(declare transparent-type-fn-1 ((TransparentTypeTest IFix) -> IFix))
27+
(define (transparent-type-fn-1 (TransparentTypeTest x))
28+
(coalton-library/lisparray:aref x 0))
29+
)
30+
31+
(in-package #:coalton-tests)
32+
33+
(deftest test-lisp-types ()
34+
(let ((env coalton-impl/entry:*global-environment*))
35+
(labels ((coalton-type (name)
36+
(coalton-impl/typechecker/environment:type-entry-type
37+
(coalton-impl/typechecker/environment:lookup-type env name)))
38+
(coalton-type-of (value-name)
39+
(coalton-impl/typechecker/environment:lookup-value-type env value-name))
40+
(coalton-type-of-arg1 (value-name)
41+
(car (coalton-impl/typechecker/types:function-type-arguments
42+
(coalton-type-of value-name))))
43+
(lisp-type (coalton-type)
44+
(coalton-impl/typechecker/lisp-type:lisp-type coalton-type env)))
45+
46+
;; Concrete type mappings
47+
(is (equal 'single-float (lisp-type (coalton-type 'coalton:single-float))))
48+
(is (equal 'double-float (lisp-type (coalton-type 'coalton:double-float))))
49+
50+
;; A few special cases
51+
(is (equal '(or number coalton-library/math/complex:complex)
52+
(lisp-type (coalton-type-of-arg1 'coalton-native-tests::complex-type-fn))))
53+
(is (equal '(complex double-float)
54+
(lisp-type (coalton-type-of-arg1 'coalton-native-tests::complex-type-fn-1))))
55+
(is (equal '(simple-array * (*))
56+
(lisp-type (coalton-type-of-arg1 'coalton-native-tests::lisp-array-fn))))
57+
(is (equal '(simple-array fixnum (*))
58+
(lisp-type (coalton-type-of-arg1 'coalton-native-tests::lisp-array-fn-1))))
59+
60+
;; Transparent type
61+
(is (equal 'coalton-impl/runtime/function-entry:function-entry
62+
(lisp-type (coalton-type-of 'coalton-native-tests::transparent-type-fn))))
63+
(is (equal '(simple-array * (*))
64+
(lisp-type (coalton-type-of-arg1 'coalton-native-tests::transparent-type-fn))))
65+
(is (equal '(simple-array fixnum (*))
66+
(lisp-type (coalton-type-of-arg1 'coalton-native-tests::transparent-type-fn-1))))
67+
)))

0 commit comments

Comments
 (0)