Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better row unification error messages #4421

Open
wants to merge 47 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
4975df0
Try to show which labels are mismatched as well
FredTheDino Nov 29, 2022
47aff37
Revert "Try to show which labels are mismatched as well"
FredTheDino Dec 4, 2022
7b4c4d6
Display a merged error message
FredTheDino Dec 4, 2022
c0cd73d
Revert "Display a merged error message"
FredTheDino Dec 16, 2022
ef71d77
Add testcases for more record errors
FredTheDino Dec 19, 2022
b5e4f81
Add test output before changes
FredTheDino Dec 19, 2022
335b873
Change the error generation code
FredTheDino Dec 16, 2022
5969058
Change a sequence into a parU
FredTheDino Dec 16, 2022
3cb3074
Update the test output after changes
FredTheDino Dec 19, 2022
9c1c4f4
Add test for parU change
FredTheDino Dec 19, 2022
fe37bdc
Merge remote-tracking branch 'origin/master' into HEAD
MonoidMusician Feb 1, 2023
7041b93
Commit test changes from merge
MonoidMusician Feb 1, 2023
48c33f6
Merge remote-tracking branch 'origin/master' into types-do-not-unify-…
JordanMartinez Aug 7, 2023
03ba84a
Make types in error message different
JordanMartinez Aug 7, 2023
af8260b
Report both errors in nested error
JordanMartinez Aug 8, 2023
d4cf721
Test out substituteType approach
JordanMartinez Aug 8, 2023
fa7235f
Revert "Test out substituteType approach"
JordanMartinez Aug 8, 2023
ed9bcd9
Show `master`'s output of added tests
JordanMartinez Aug 8, 2023
0ae5f1f
Revert "Show `master`'s output of added tests"
JordanMartinez Aug 8, 2023
f9a8aad
Commit output of dropping `parU`
JordanMartinez Aug 8, 2023
7a160d4
Simplify using parU to get all errors
JordanMartinez Aug 8, 2023
48516ea
Merge remote-tracking branch 'origin/master' into types-do-not-unify-…
JordanMartinez Aug 8, 2023
958c954
Use `parU` to fix multi errors in 1 row test
JordanMartinez Aug 8, 2023
25b8c10
Add another test showing shared/unshared labels
JordanMartinez Aug 8, 2023
c7566f9
Cleanup comments
JordanMartinez Aug 8, 2023
f7ec585
Rework unifyRows error handling
rhendric Aug 8, 2023
cb9031a
Generalize unifyRows to unifyishRows
JordanMartinez Aug 9, 2023
5bae146
Update subsumes to use unifyishRows
JordanMartinez Aug 9, 2023
14702f7
Add Ryan's kind unification test
JordanMartinez Aug 9, 2023
f70c8d9
Update unifyKindsWithFailure to use unifyishRows sometimes
JordanMartinez Aug 9, 2023
93617e1
A little fussing before the action
rhendric Aug 10, 2023
5fa4ea0
Refactor record subsumption, unifyRows
rhendric Aug 10, 2023
b80d3d3
Add used-x-expected-y bit to TypesDoNotUnify
rhendric Aug 10, 2023
de51a65
Rework checkProperties
rhendric Aug 10, 2023
28f4dff
Update tests
rhendric Aug 10, 2023
7202333
Error improvement: drop redundant subsumption hint
rhendric Aug 10, 2023
d02efa1
Error improvement: diff records like rows
rhendric Aug 10, 2023
6acdd99
Error improvement: display empty records as such
rhendric Aug 10, 2023
7ceba4c
Appease HLint
rhendric Aug 10, 2023
97b6b86
Update Kinds to always use unifyishRows
JordanMartinez Aug 10, 2023
9b54c4c
Use actual/expected terminology
JordanMartinez Aug 10, 2023
cee90c4
Merge remote-tracking branch 'origin/master' into better-unify-row-er…
JordanMartinez Aug 10, 2023
75aa382
First attempt at changelog entry
JordanMartinez Aug 10, 2023
09567b6
Update entry: apparent pattern matching inconsistency
JordanMartinez Aug 10, 2023
5b56006
Use 'expected but found' terminology
JordanMartinez Aug 10, 2023
6b60710
Use Ryan's suggestion to merge cases 2-4
JordanMartinez Aug 10, 2023
2094d75
Fix 'expected/actual' header text; reword opening
JordanMartinez Aug 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 50 additions & 35 deletions src/Language/PureScript/Errors.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Control.Arrow ((&&&))
import Control.Exception (displayException)
import Control.Lens (both, head1, over)
import Control.Monad (forM, unless)
import Control.Monad.Error.Class (MonadError(..))
import Control.Monad.Error.Class (MonadError(..), liftEither)
import Control.Monad.Trans.State.Lazy (State, evalState, get, put)
import Control.Monad.Writer (Last(..), MonadWriter(..), censor)
import Data.Bifunctor (first, second)
Expand Down Expand Up @@ -47,7 +47,7 @@ import Language.PureScript.Pretty.Common (endWith)
import Language.PureScript.PSString (decodeStringWithReplacement)
import Language.PureScript.Roles (Role, displayRole)
import Language.PureScript.Traversals (sndM)
import Language.PureScript.Types (Constraint(..), ConstraintData(..), RowListItem(..), SourceConstraint, SourceType, Type(..), eraseForAllKindAnnotations, eraseKindApps, everywhereOnTypesTopDownM, getAnnForType, isMonoType, overConstraintArgs, rowFromList, rowToList, srcTUnknown)
import Language.PureScript.Types (Constraint(..), ConstraintData(..), RowListItem(..), SourceConstraint, SourceType, Type(..), eqType, eraseForAllKindAnnotations, eraseKindApps, everywhereOnTypesTopDownM, getAnnForType, isMonoType, overConstraintArgs, rowFromList, rowToList, srcTUnknown)
import Language.PureScript.Publish.BoxesHelpers qualified as BoxHelpers
import System.Console.ANSI qualified as ANSI
import System.FilePath (makeRelative)
Expand Down Expand Up @@ -104,7 +104,10 @@ data SimpleErrorMessage
| UndefinedTypeVariable (ProperName 'TypeName)
| PartiallyAppliedSynonym (Qualified (ProperName 'TypeName))
| EscapedSkolem Text (Maybe SourceSpan) SourceType
| TypesDoNotUnify SourceType SourceType
| TypesDoNotUnify
Bool -- ^ if this error is known to be a case where the first type is used but the second type is expected
SourceType
SourceType
| KindsDoNotUnify SourceType SourceType
| ConstrainedTypeUnified SourceType SourceType
| OverlappingInstances (Qualified (ProperName 'ClassName)) [SourceType] [Qualified (Either SourceType Ident)]
Expand Down Expand Up @@ -132,9 +135,6 @@ data SimpleErrorMessage
| ExpectedType SourceType SourceType
-- | constructor name, expected argument count, actual argument count
| IncorrectConstructorArity (Qualified (ProperName 'ConstructorName)) Int Int
| ExprDoesNotHaveType Expr SourceType
| PropertyIsMissing Label
| AdditionalProperty Label
| OrphanInstance Ident (Qualified (ProperName 'ClassName)) (S.Set ModuleName) [SourceType]
| InvalidNewtype (ProperName 'TypeName)
| InvalidInstanceHead SourceType
Expand Down Expand Up @@ -309,9 +309,6 @@ errorCode em = case unwrapErrorMessage em of
ExtraneousClassMember{} -> "ExtraneousClassMember"
ExpectedType{} -> "ExpectedType"
IncorrectConstructorArity{} -> "IncorrectConstructorArity"
ExprDoesNotHaveType{} -> "ExprDoesNotHaveType"
PropertyIsMissing{} -> "PropertyIsMissing"
AdditionalProperty{} -> "AdditionalProperty"
OrphanInstance{} -> "OrphanInstance"
InvalidNewtype{} -> "InvalidNewtype"
InvalidInstanceHead{} -> "InvalidInstanceHead"
Expand Down Expand Up @@ -466,9 +463,8 @@ onTypesInErrorMessageM :: Applicative m => (SourceType -> m SourceType) -> Error
onTypesInErrorMessageM f (ErrorMessage hints simple) = ErrorMessage <$> traverse gHint hints <*> gSimple simple
where
gSimple (InfiniteType t) = InfiniteType <$> f t
gSimple (TypesDoNotUnify t1 t2) = TypesDoNotUnify <$> f t1 <*> f t2
gSimple (TypesDoNotUnify isOrdered t1 t2) = TypesDoNotUnify isOrdered <$> f t1 <*> f t2
gSimple (ConstrainedTypeUnified t1 t2) = ConstrainedTypeUnified <$> f t1 <*> f t2
gSimple (ExprDoesNotHaveType e t) = ExprDoesNotHaveType e <$> f t
gSimple (InvalidInstanceHead t) = InvalidInstanceHead <$> f t
gSimple (NoInstanceFound con ambig unks) = NoInstanceFound <$> overConstraintArgs (traverse f) con <*> pure ambig <*> pure unks
gSimple (AmbiguousTypeVariables t uis) = AmbiguousTypeVariables <$> f t <*> pure uis
Expand Down Expand Up @@ -858,14 +854,21 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs relPath fileCon
, line "has escaped its scope, appearing in the type"
, markCodeBox $ indent $ prettyType ty
]
renderSimpleErrorMessage (TypesDoNotUnify u1 u2)
renderSimpleErrorMessage (TypesDoNotUnify isOrdered u1 u2)
= let (row1Box, row2Box) = printRows u1 u2

in paras [ line "Could not match type"
, row1Box
, line "with type"
, row2Box
]
in if isOrdered then
paras [ line "The type"
, row1Box
, line "does not match the expected type"
JordanMartinez marked this conversation as resolved.
Show resolved Hide resolved
, row2Box
]
else
paras [ line "Could not match type"
, row1Box
, line "with type"
, row2Box
]

renderSimpleErrorMessage (KindsDoNotUnify k1 k2) =
paras [ line "Could not match kind"
Expand Down Expand Up @@ -1048,16 +1051,6 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs relPath fileCon
paras [ line $ "Data constructor " <> markCode (showQualified runProperName nm) <> " was given " <> T.pack (show actual) <> " arguments in a case expression, but expected " <> T.pack (show expected) <> " arguments."
, line $ "This problem can be fixed by giving " <> markCode (showQualified runProperName nm) <> " " <> T.pack (show expected) <> " arguments."
]
renderSimpleErrorMessage (ExprDoesNotHaveType expr ty) =
paras [ line "Expression"
, markCodeBox $ indent $ prettyPrintValue prettyDepth expr
, line "does not have type"
, markCodeBox $ indent $ prettyType ty
]
renderSimpleErrorMessage (PropertyIsMissing prop) =
line $ "Type of expression lacks required label " <> markCode (prettyPrintLabel prop) <> "."
renderSimpleErrorMessage (AdditionalProperty prop) =
line $ "Type of expression contains additional label " <> markCode (prettyPrintLabel prop) <> "."
renderSimpleErrorMessage (OrphanInstance nm cnm nonOrphanModules ts) =
paras [ line $ "Orphan instance" <> prettyPrintPlainIdent nm <> " found for "
, markCodeBox $ indent $ Box.hsep 1 Box.left
Expand Down Expand Up @@ -1614,6 +1607,10 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs relPath fileCon
let (sorted1, sorted2) = filterRows (rowToList r1) (rowToList r2)
in (printRow typeDiffAsBox sorted1, printRow typeDiffAsBox sorted2)

(_, TypeApp s1 f1@(TypeConstructor _ C.Record) r1'@RCons{}, TypeApp s2 f2@(TypeConstructor _ C.Record) r2'@RCons{}) ->
let (sorted1, sorted2) = filterRows (rowToList r1') (rowToList r2')
in (printRow typeDiffAsBox $ TypeApp s1 f1 sorted1, printRow typeDiffAsBox $ TypeApp s2 f2 sorted2)

(_, _, _) -> (printRow typeAsBox r1, printRow typeAsBox r2)


Expand Down Expand Up @@ -1724,14 +1721,12 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs relPath fileCon

-- See https://github.com/purescript/purescript/issues/1802
stripRedundantHints :: SimpleErrorMessage -> [ErrorMessageHint] -> [ErrorMessageHint]
stripRedundantHints ExprDoesNotHaveType{} = stripFirst isCheckHint
where
isCheckHint ErrorCheckingType{} = True
isCheckHint _ = False
stripRedundantHints TypesDoNotUnify{} = stripFirst isUnifyHint
stripRedundantHints (TypesDoNotUnify _ t1 t2) = stripFirst isMatchingSubsumptionHint . stripFirst isUnifyHint
where
isUnifyHint ErrorUnifyingTypes{} = True
isUnifyHint _ = False
isMatchingSubsumptionHint (ErrorInSubsumption t1' t2') = t1 `eqType` t1' && t2 `eqType` t2'
isMatchingSubsumptionHint _ = False
stripRedundantHints (NoInstanceFound (Constraint _ C.Coercible _ args _) _ _) = filter (not . isSolverHint)
where
isSolverHint (ErrorSolvingConstraint (Constraint _ C.Coercible _ args' _)) = args == args'
Expand Down Expand Up @@ -2049,16 +2044,36 @@ parU
-> (a -> m b)
-> m [b]
parU xs f =
forM xs (withError . f) >>= collectErrors
forM xs (tryError . f) >>= collectErrors
where
withError :: m b -> m (Either MultipleErrors b)
withError u = catchError (Right <$> u) (return . Left)
-- exported from Control.Monad.Error.Class in mtl >= 2.3
tryError :: m b -> m (Either MultipleErrors b)
tryError u = catchError (Right <$> u) (return . Left)

collectErrors :: [Either MultipleErrors b] -> m [b]
collectErrors es = case partitionEithers es of
([], rs) -> return rs
(errs, _) -> throwError $ fold errs

-- | Collect errors in parallel, using a function to combine results
liftParU2
:: forall m a b c
. MonadError MultipleErrors m
=> (a -> b -> c)
-> m a
-> m b
-> m c
liftParU2 f ma mb = f' <$> tryError ma <*> tryError mb >>= liftEither
where
-- exported from Control.Monad.Error.Class in mtl >= 2.3
tryError :: forall d. m d -> m (Either MultipleErrors d)
tryError u = catchError (Right <$> u) (return . Left)

f' (Left e) (Left e') = Left $ e <> e'
f' (Left e) (Right _) = Left e
f' (Right _) (Left e) = Left e
f' (Right a) (Right b) = Right $ f a b

internalCompilerError
:: (MonadError MultipleErrors m, GHC.Stack.HasCallStack)
=> Text
Expand Down
9 changes: 7 additions & 2 deletions src/Language/PureScript/Pretty/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,15 @@ convertPrettyPrintType = go
goTypeApp d (TypeApp _ f a) b
| eqType f tyFunction = PPFunction (go (d-1) a) (go (d-1) b)
| otherwise = PPTypeApp (goTypeApp d f a) (go (d-1) b)
goTypeApp d o ty@RCons{}
| eqType o tyRecord = uncurry PPRecord (goRow d ty)
goTypeApp d o ty
| eqType o tyRecord, isConsOrEmpty ty = uncurry PPRecord (goRow d ty)
goTypeApp d a b = PPTypeApp (go (d-1) a) (go (d-1) b)

isConsOrEmpty = \case
RCons{} -> True
REmpty{} -> True
_ -> False

-- TODO(Christoph): get rid of T.unpack s

constraintsAsBox :: TypeRenderOptions -> PrettyPrintConstraint -> Box -> Box
Expand Down
4 changes: 2 additions & 2 deletions src/Language/PureScript/TypeChecker/Entailment/Coercible.hs
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ canonRow a b
(deriveds, (([], tail1), ([], tail2))) -> do
pure . Canonicalized . S.fromList $ (tail1, tail2) : deriveds
(_, (rl1, rl2)) ->
throwError . errorMessage $ TypesDoNotUnify (rowFromList rl1) (rowFromList rl2)
throwError . errorMessage $ TypesDoNotUnify False (rowFromList rl1) (rowFromList rl2)
| otherwise = empty

-- | Unwrapping a newtype can fails in two ways:
Expand Down Expand Up @@ -768,7 +768,7 @@ decompose env tyName axs bxs = do
| ax == bx ->
pure mempty
| otherwise ->
throwError . errorMessage $ TypesDoNotUnify ax bx
throwError . errorMessage $ TypesDoNotUnify False ax bx
Representational ->
pure $ S.singleton (ax, bx)
Phantom ->
Expand Down
53 changes: 23 additions & 30 deletions src/Language/PureScript/TypeChecker/Kinds.hs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ unifyKinds
=> SourceType
-> SourceType
-> m ()
unifyKinds = unifyKindsWithFailure $ UseUnifyishRows isKindsDoNotUnify $ \w1 w2 ->
unifyKinds = unifyKindsWithFailure UseUnifyishRows $ \w1 w2 ->
pure
$ errorMessage''' (fst . getAnnForType <$> [w1, w2])
$ KindsDoNotUnify w1 w2
Expand All @@ -398,7 +398,7 @@ unifyKinds'
=> SourceType
-> SourceType
-> m ()
unifyKinds' = unifyKindsWithFailure $ UseUnifyishRows isKindsDoNotUnify $ \w1 w2 ->
unifyKinds' = unifyKindsWithFailure UseUnifyishRows $ \w1 w2 ->
pure
$ errorMessage
$ KindsDoNotUnify w1 w2
Expand All @@ -414,36 +414,31 @@ checkTypeKind ty kind =
-- So, rather than use `unifyishRows` here and pay for its overhead,
-- we'll use the approach that was used before we migrated to `unifyishRows`
-- because the original approach fails faster.
unifyKindsWithFailure (UseSequential ty kind) kind E.kindType
unifyKindsWithFailure UseSequential
(\_ _ -> pure $ errorMessage $ ExpectedType ty kind)
kind
E.kindType

data UnifyRowOptions m
-- type kind
= UseSequential SourceType SourceType
-- isExpectedError onFailure
| UseUnifyishRows (SimpleErrorMessage -> Bool) (SourceType -> SourceType -> m MultipleErrors)
data UnifyRowOptions
= UseSequential
| UseUnifyishRows

unifyKindsWithFailure
:: (MonadError MultipleErrors m, MonadState CheckState m, HasCallStack)
=> UnifyRowOptions m
=> UnifyRowOptions
-> (SourceType -> SourceType -> m MultipleErrors)
-> SourceType
-> SourceType
-> m ()
unifyKindsWithFailure opts = go
unifyKindsWithFailure opts onFailure = go
where
(unifyRows, onFailure) = case opts of
UseSequential ty kind ->
( \r1 r2 -> do
let (matches, rest) = alignRowsWith (\_ -> go) r1 r2
sequence_ matches
void $ unifyTails rest

, \_ _ ->
pure $ errorMessage $ ExpectedType ty kind
)
UseUnifyishRows isExpectedError buildError ->
( unifyishRows go unifyTails isExpectedError buildError
, buildError
)
unifyRows = case opts of
UseSequential -> \r1 r2 -> do
let (matches, rest) = alignRowsWith (const go) r1 r2
sequence_ matches
void $ unifyTails rest
UseUnifyishRows ->
unifyishRows unifyTails isKindsDoNotUnify onFailure go

go = curry $ \case
(TypeApp _ p1 p2, TypeApp _ p3 p4) -> do
Expand All @@ -470,12 +465,10 @@ unifyKindsWithFailure opts = go
throwError =<< onFailure w1 w2

unifyTails = \case
(([], TUnknown _ a'), (rs, p1)) -> do
solveUnknown a' $ rowFromList (rs, p1)
pure True
((rs, p1), ([], TUnknown _ a')) -> do
solveUnknown a' $ rowFromList (rs, p1)
pure True
(([], TUnknown _ a'), (rs, p1)) ->
solveUnknown a' (rowFromList (rs, p1)) $> True
((rs, p1), ([], TUnknown _ a')) ->
solveUnknown a' (rowFromList (rs, p1)) $> True
(([], w1), ([], w2)) | eqType w1 w2 ->
pure True
((rs1, TUnknown _ u1), (rs2, TUnknown _ u2)) | u1 /= u2 -> do
Expand Down
35 changes: 10 additions & 25 deletions src/Language/PureScript/TypeChecker/Subsumption.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import Control.Monad.Error.Class (MonadError(..))
import Control.Monad.State.Class (MonadState(..), gets)

import Language.PureScript.AST (ErrorMessageHint(..), Expr(..), pattern NullSourceAnn)
import Language.PureScript.Constants.Prim qualified as C
import Language.PureScript.Crash (internalError)
import Language.PureScript.Environment (tyFunction, tyRecord)
import Language.PureScript.Errors (MultipleErrors, SimpleErrorMessage(..), errorMessage, internalCompilerError)
import Language.PureScript.Environment (tyFunction)
import Language.PureScript.Errors (MultipleErrors, internalCompilerError)
import Language.PureScript.TypeChecker.Monad (CheckState(..), getHints, getTypeClassDictionaries, withErrorMessageHint)
import Language.PureScript.TypeChecker.Skolems (newSkolemConstant, skolemize)
import Language.PureScript.TypeChecker.Unify (freshTypeWithKind, substituteType, unifyTypes)
import Language.PureScript.TypeChecker.Unify.Rows (unifyishRows, isTypesDoNotUnify)
import Language.PureScript.Types (SourceType, Type(..), eqType, replaceTypeVars, rowFromList)
import Language.PureScript.TypeChecker.Unify (freshTypeWithKind, substituteType, unifyishRowTypes, unifyTypesOrdered)
import Language.PureScript.Types (SourceType, Type(..), eqType, replaceTypeVars)

-- | Subsumption can operate in two modes:
--
Expand Down Expand Up @@ -52,7 +52,7 @@ defaultCoercion :: ModeSing mode -> Coercion mode
defaultCoercion SElaborate = id
defaultCoercion SNoElaborate = ()

-- | Check that one type subsumes another, rethrowing errors to provide a better error message
-- | Check that one type (ty2) subsumes another (ty1), rethrowing errors to provide a better error message
subsumes
:: (MonadError MultipleErrors m, MonadState CheckState m)
=> SourceType
Expand Down Expand Up @@ -98,27 +98,12 @@ subsumes' SElaborate (ConstrainedType _ con ty1) ty2 = do
elaborate <- subsumes' SElaborate ty1 ty2
let addDicts val = App val (TypeClassDictionary con dicts hints)
return (elaborate . addDicts)
subsumes' mode (TypeApp _ f1 r1) (TypeApp _ f2 r2) | eqType f1 tyRecord && eqType f2 tyRecord = do
let
withBoolError :: forall a. m a -> m Bool
withBoolError u = catchError (True <$ u) (pure . const False)
unifyishRows
-- Check subsumption for common labels
(subsumes' SNoElaborate)
-- Inject the info here
(uncurry $ \(ts1', r1') (ts2', r2') ->
withBoolError $ unifyTypes (rowFromList (ts1', r1')) (rowFromList (ts2', r2')))
isTypesDoNotUnify
(\r1' r2' -> do
subst <- gets checkSubstitution
pure $ errorMessage $ TypesDoNotUnify (substituteType subst r1') (substituteType subst r2'))
r1
r2
subsumes' mode (TypeApp s1 f1@(TypeConstructor _ C.Record) r1) (TypeApp s2 f2@(TypeConstructor _ C.Record) r2) = do
subst <- gets checkSubstitution
unifyishRowTypes True (TypeApp s1 f1) (TypeApp s2 f2) (subsumes' SNoElaborate) (substituteType subst r1) (substituteType subst r2)
JordanMartinez marked this conversation as resolved.
Show resolved Hide resolved
-- Nothing was elaborated, return the default coercion
return (defaultCoercion mode)
subsumes' mode ty1 ty2@(TypeApp _ obj _) | obj == tyRecord =
subsumes' mode ty2 ty1
JordanMartinez marked this conversation as resolved.
Show resolved Hide resolved
subsumes' mode ty1 ty2 = do
unifyTypes ty1 ty2
unifyTypesOrdered ty1 ty2
-- Nothing was elaborated, return the default coercion
return (defaultCoercion mode)