diff --git a/src/typechecker/context-reduction.lisp b/src/typechecker/context-reduction.lisp index fb4a09f2e..a24322412 100644 --- a/src/typechecker/context-reduction.lisp +++ b/src/typechecker/context-reduction.lisp @@ -268,11 +268,28 @@ Returns (VALUES deferred-preds retained-preds defaultable-preds)" :do (setf subs (compose-substitution-lists subs (fundep-entail% env expr-preds pred known-tyvars))) :finally (return subs))) +(defun expand-pred-into-superclasses (env pred) + "This function finds the class in ENV associated with PRED and +recursively appends superclass predicates, with appropriate type +substitutions." + (declare (type environment env) + (type ty-predicate pred) + (values ty-predicate-list &optional)) + (let* ((class (lookup-class env (ty-predicate-class pred))) + (subs (mapcan #'match + (ty-predicate-types (ty-class-predicate class)) + (ty-predicate-types pred)))) + (cons pred (loop :for super-pred :in (ty-class-superclasses class) + :for corrected-super-pred := (apply-substitution subs super-pred) + :append (expand-pred-into-superclasses env corrected-super-pred))))) + (defun fundep-entail% (env expr-preds pred known-tyvars) (let ((class (lookup-class env (ty-predicate-class pred)))) (unless (ty-class-fundeps class) (return-from fundep-entail% nil)) + (setf expr-preds (mapcan (lambda (p) (expand-pred-into-superclasses env p)) expr-preds)) + (let* ((unknown-indices nil) (known-indices diff --git a/tests/fundep-tests.lisp b/tests/fundep-tests.lisp index 0ebc2fbae..86c09ef65 100644 --- a/tests/fundep-tests.lisp +++ b/tests/fundep-tests.lisp @@ -147,3 +147,19 @@ (let ((filled? (fn (i) (coalton-library/optional:some? (moo-find moo i))))) (coalton-library/iterator:filter! filled? (coalton-library/iterator:up-to (moo-size moo)))))")) + +(deftest fundep-superclass-resolution () + ;; See https://github.com/coalton-lang/coalton/issues/1050 + (check-coalton-types + "(define-class (RandomAccessBase :f :t (:f -> :t)) + (make (UFix -> :t -> :f)) + (rab-length (:f -> UFix))) + + (define-class (RandomAccessBase :f :t => RandomAccessReadable :f :t (:f -> :t)) + (unsafe-set! (:f -> UFix -> :t))) + + (declare aref (RandomAccessReadable :f :t => :f -> UFix -> (Optional :t))) + (define (aref storage index) + (if (and (<= 0 index) (< index (rab-length storage))) + (Some (unsafe-set! storage index)) + None)))"))