4e987026 |
;;; Before classes are converted, the super class relation is computed.
;;; This sets up the super and super* field of each class and
;;; checks for the following errors:
;;; Wrong tyvar in context
;;; cyclic class structure
;;; Non-class in context
(define (compute-super-classes modules)
(let ((all-classes '()))
(walk-modules modules
(lambda ()
(dolist (c (module-classes *module*))
(remember-context c
(with-slots class-decl (super-classes class class-var) c
(let* ((def (class-ref-class class))
(local-ctxts '())
(super '()))
(dolist (context super-classes)
(with-slots context (class tyvar) context
(when (not (eq? class-var tyvar))
(signal-super-class-tyvar-error class class-var tyvar))
(resolve-class class)
(let ((super-def (class-ref-class class)))
(when (not (eq? super-def *undefined-def*))
(push super-def super)
(when (eq? *unit* (def-unit super-def))
(push super-def local-ctxts))))))
(update-slots class def
(super super)
(tyvar class-var))
(push (cons def local-ctxts) all-classes)))))))
(multiple-value-bind (status sorted) (topsort all-classes)
(when (eq? status 'cyclic)
(signal-cyclic-class-structure sorted))
(dolist (c sorted)
(let* ((super (class-super c))
(super* super))
(dolist (s super)
(setf super* (set-union super* (class-super* s)))
(setf (class-super* c) super*)))))))
(define (signal-super-class-tyvar-error class class-var tyvar)
(recoverable-error 'super-class-tyvar-error
"The context for class ~A must only refer to type variable ~A.~%~
Type variable ~A cannot be used here."
(class-ref-name class) class-var tyvar))
(define (signal-cyclic-class-structure classes)
(fatal-error 'cyclic-class-structure
"There is a cycle in the superclass relation involving these classes:~%~a"
classes))
;;; This sets up the following fields in the class entry:
;;; instances '()
;;; defaults = ast for defaults
;;; kind
;;; methods
;;; signatures
;;; method-vars
;;; selectors
;;; Each method is initialized with
;;; class
;;; signature
;;; type
;;; Errors detected:
;;; signature doesnt reference class
(define (class->def class-decl)
(remember-context class-decl
(let* ((class (class-ref-class (class-decl-class class-decl)))
(decls (class-decl-decls class-decl)))
(setf (class-instances class) '())
(setf (class-kind class) (find-class-kind class))
(init-methods class decls) ; sets up defaults, method signatures
(setf (class-n-methods class) (length (class-method-vars class)))
(setf (class-dict-size class)
(+ (class-n-methods class) (length (class-super* class))))
class)))
(define (find-class-kind class)
(cond ((not (module-prelude? *module*))
'other)
((memq class
(list (core-symbol "Eq") (core-symbol "Ord")
(core-symbol "Text") (core-symbol "Binary")
(core-symbol "Ix") (core-symbol "Enum")))
'Standard)
((memq class
(list (core-symbol "Num") (core-symbol "Real")
(core-symbol "Integral") (core-symbol "Fractional")
(core-symbol "Floating") (core-symbol "RealFrac")
(core-symbol "RealFloat")))
'Numeric)
(else
'other)))
(define (init-methods class decls)
(let* ((tyvar (class-tyvar class))
(class-context (**context (**class/def class) tyvar)))
(dolist (decl decls)
(remember-context decl
(cond ((is-type? 'signdecl decl)
(let* ((signature (signdecl-signature decl))
(vars (resolve-signature signature)))
(when (not (memq tyvar vars))
(signal-class-sig-ignores-type signature))
;; Note: signature does not include defined class yet
(dolist (context (signature-context signature))
(when (eq? tyvar (context-tyvar context))
(signal-method-constrains-class-tyvar context)))
(setf signature (rename-class-sig-vars signature tyvar))
(let ((gtype (ast->gtype (cons class-context
(signature-context signature))
(signature-type signature))))
(dolist (var-ref (signdecl-vars decl))
(let ((var (var-ref-var var-ref)))
(setf (var-type var) gtype)
(setf (method-var-method-signature var) signature))))))
(else ; decl must be a default definition
(let ((vars (collect-pattern-vars (valdef-lhs decl))))
(dolist (var-ref vars)
(resolve-var var-ref)
(let* ((method-name (var-ref-name var-ref))
(method-var (var-ref-var var-ref)))
(when (not (eq? method-var *undefined-def*))
(if (and (method-var? method-var)
(eq? (method-var-class method-var) class))
(let ((default-var
(make-new-var
(string-append
"default-"
(symbol->string (def-name method-var))))))
(setf (var-ref-var var-ref) default-var)
(setf (var-ref-name var-ref) (def-name default-var))
(when (not (eq? (method-var-default method-var) '#f))
(signal-multiple-definition-of-default method-name))
(setf (method-var-default method-var) default-var)
(let* ((sig (method-var-method-signature method-var))
(context (cons class-context
(signature-context sig)))
(new-sig (**signature context
(signature-type sig))))
(add-new-module-signature default-var new-sig)))
(signal-default-not-in-class method-var class)))))
(add-new-module-decl decl))))))))
(define (signal-class-sig-ignores-type signature)
(phase-error 'class-sig-ignores-type
"The method signature ~a does not reference the overloaded type."
signature))
;;; *** I don't understand this message.
(define (signal-method-constrains-class-tyvar context)
(phase-error 'method-constrains-class-tyvar
"Individual methods may not further constrain a class: ~A" context))
;;; *** I don't understand this message.
(define (signal-multiple-definition-of-default method-name)
(phase-error 'multiple-definition-of-default
"More that one default for ~A."
method-name))
;;; *** I don't understand this message.
(define (signal-default-not-in-class method-var class)
(phase-error 'default-not-in-class
"~A is not a method in class ~A."
method-var class))
(define (create-selector-functions class)
(let ((res '()))
(dolist (c (cons class (class-super* class)))
(dolist (m (class-method-vars c))
(let* ((var (make-new-var
(string-append "sel-"
(symbol->string (def-name class))
"/"
(symbol->string (def-name m)))))
(sel-body (create-selector-code class m)))
(setf (var-selector-fn? var) '#t)
(push (tuple m var) res)
(when (not (eq? (module-type *module*) 'interface))
(add-new-module-def var sel-body)))))
res))
(define (create-selector-code c m)
(let ((var (create-local-definition '|d|)))
(setf (var-force-strict? var) '#t)
(let ((body (create-selector-code-1 c m (**var/def var))))
(**lambda/pat (list (**var-pat/def var)) body))))
(define (create-selector-code-1 class method d)
(let ((mcl (method-var-class method)))
(cond ((eq? mcl class)
(**dsel/method class method d))
(else
(**dsel/method mcl method (**dsel/dict class mcl d))))))
;;; The following code is for the alpha conversion of method
;;; signatures. The class tyvar is unchanged; all others are renamed.
;;; This is needed because all method types are combined to form the
;;; dictionary signature and aliasing among different tyvars should be
;;; prevented.
(define (rename-class-sig-vars signature tyvar)
(mlet (((new-context env1)
(rename-context-vars (signature-context signature)
(list (tuple tyvar tyvar))))
((new-type _)
(rename-type-vars (signature-type signature) env1)))
(**signature new-context new-type)))
(define (rename-context-vars contexts env)
(if (null? contexts)
(values '() env)
(mlet (((new-tyvar env1)
(rename-sig-tyvar (context-tyvar (car contexts)) env))
((rest env2)
(rename-context-vars (cdr contexts) env1)))
(values (cons (**context (context-class (car contexts)) new-tyvar) rest)
env2))))
(define (rename-type-vars type env)
(if (tyvar? type)
(mlet (((tyvar env1)
(rename-sig-tyvar (tyvar-name type) env)))
(values (**tyvar tyvar) env1))
(mlet (((new-types env1) (rename-type-vars/l (tycon-args type) env)))
(values (**tycon/def (tycon-def type) new-types) env1))))
(define (rename-type-vars/l types env)
(if (null? types)
(values '() env)
(mlet (((type1 env1) (rename-type-vars (car types) env))
((new-types env2) (rename-type-vars/l (cdr types) env1)))
(values (cons type1 new-types) env2))))
(define (rename-sig-tyvar tyvar env)
(let ((res (assq tyvar env)))
(if (eq? res '#f)
(let ((new-tyvar (gentyvar (symbol->string tyvar))))
(values new-tyvar (cons (tuple tyvar new-tyvar) env)))
(values (tuple-2-2 res) env))))
(define *tyvar-counter* 0)
;;; This generates a new interned tyvar name
(define (gentyvar root)
(incf *tyvar-counter*)
(string->symbol (format '#f "~A-~A" root *tyvar-counter*)))
|