Skip to content

Commit 2ec27cf

Browse files
committed
Instantiate types in record literals as necessary
1 parent 5ff1286 commit 2ec27cf

File tree

2 files changed

+53
-17
lines changed

2 files changed

+53
-17
lines changed

examples/passing/1110.purs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module Main where
2+
3+
import Prelude
4+
import Control.Monad.Eff.Console (log)
5+
6+
data X a = X
7+
8+
x :: forall a. X a
9+
x = X
10+
11+
type Y = { x :: X Int }
12+
13+
test :: forall m. Monad m => m Y
14+
test = pure { x: x }
15+
16+
main = log "Done"

src/Language/PureScript/TypeChecker/Types.hs

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ checkTypedBindingGroupElement mn (ident, (val, ty, checkType)) dict = do
241241
ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty
242242
-- Check the type with the new names in scope
243243
val' <- if checkType
244-
then withScopedTypeVars mn args $ bindNames dict $ TypedValue True <$> check val ty' <*> pure ty'
244+
then withScopedTypeVars mn args $ bindNames dict $ check val ty'
245245
else return (TypedValue False val ty')
246246
return (ident, (val', ty'))
247247

@@ -297,7 +297,8 @@ infer val = withErrorMessageHint (ErrorInferringType val) $ infer' val
297297

298298
-- | Infer a type for a value
299299
infer'
300-
:: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
300+
:: forall m
301+
. (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
301302
=> Expr
302303
-> m Expr
303304
infer' v@(Literal (NumericLiteral (Left _))) = return $ TypedValue True v tyInt
@@ -315,10 +316,25 @@ infer' (Literal (ArrayLiteral vals)) = do
315316
return $ TypedValue True (Literal (ArrayLiteral ts')) (TypeApp tyArray els)
316317
infer' (Literal (ObjectLiteral ps)) = do
317318
ensureNoDuplicateProperties ps
318-
ts <- traverse (infer . snd) ps
319-
let fields = zipWith (\name (TypedValue _ _ t) -> (Label name, t)) (map fst ps) ts
320-
ty = TypeApp tyRecord $ rowFromList (fields, REmpty)
321-
return $ TypedValue True (Literal (ObjectLiteral (zip (map fst ps) ts))) ty
319+
-- We make a special case for Vars in record labels, since there are the
320+
-- only types of expressions for which 'infer' can return a polymorphic type.
321+
-- They need to be instantiated here.
322+
let isVar :: Expr -> Bool
323+
isVar Var{} = True
324+
isVar (TypedValue _ e _) = isVar e
325+
isVar (PositionedValue _ _ e) = isVar e
326+
isVar _ = False
327+
328+
inferProperty :: (PSString, Expr) -> m (PSString, (Expr, Type))
329+
inferProperty (name, val) = do
330+
TypedValue _ val' ty <- infer val
331+
valAndType <- if isVar val
332+
then instantiatePolyTypeWithUnknowns val' ty
333+
else pure (val', ty)
334+
pure (name, valAndType)
335+
fields <- forM ps inferProperty
336+
let ty = TypeApp tyRecord $ rowFromList (map (Label *** snd) fields, REmpty)
337+
return $ TypedValue True (Literal (ObjectLiteral (map (fmap (uncurry (TypedValue True))) fields))) ty
322338
infer' (ObjectUpdate o ps) = do
323339
ensureNoDuplicateProperties ps
324340
row <- freshType
@@ -377,7 +393,9 @@ infer' (Let ds val) = do
377393
infer' (DeferredDictionary className tys) = do
378394
dicts <- getTypeClassDictionaries
379395
hints <- gets checkHints
380-
return $ TypeClassDictionary (Constraint className tys Nothing) dicts hints
396+
return $ TypedValue False
397+
(TypeClassDictionary (Constraint className tys Nothing) dicts hints)
398+
(foldl TypeApp (TypeConstructor (fmap coerceProperName className)) tys)
381399
infer' (TypedValue checkType val ty) = do
382400
Just moduleName <- checkCurrentModule <$> get
383401
(kind, args) <- kindOfWithScopedVars ty
@@ -627,7 +645,7 @@ check' v@(Var var) ty = do
627645
ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty
628646
elaborate <- subsumes repl ty'
629647
return $ TypedValue True (elaborate v) ty'
630-
check' (DeferredDictionary className tys) _ = do
648+
check' (DeferredDictionary className tys) ty = do
631649
{-
632650
-- Here, we replace a placeholder for a superclass dictionary with a regular
633651
-- TypeClassDictionary placeholder. The reason we do this is that it is necessary to have the
@@ -636,18 +654,19 @@ check' (DeferredDictionary className tys) _ = do
636654
-}
637655
dicts <- getTypeClassDictionaries
638656
hints <- gets checkHints
639-
return $ TypeClassDictionary (Constraint className tys Nothing) dicts hints
657+
return $ TypedValue False
658+
(TypeClassDictionary (Constraint className tys Nothing) dicts hints)
659+
ty
640660
check' (TypedValue checkType val ty1) ty2 = do
641-
Just moduleName <- checkCurrentModule <$> get
642-
(kind, args) <- kindOfWithScopedVars ty1
661+
kind <- kindOf ty1
643662
checkTypeKind ty1 kind
644663
ty1' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty1
645664
ty2' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty2
646-
_ <- subsumes ty1' ty2'
665+
elaborate <- subsumes ty1' ty2'
647666
val' <- if checkType
648-
then withScopedTypeVars moduleName args (check val ty2')
649-
else return val
650-
return $ TypedValue checkType val' ty2'
667+
then check val ty1'
668+
else pure val
669+
return $ TypedValue True (TypedValue checkType (elaborate val') ty1') ty2'
651670
check' (Case vals binders) ret = do
652671
(vals', ts) <- instantiateForBinders vals binders
653672
binders' <- checkBinders ts ret binders
@@ -684,8 +703,9 @@ check' v@(Constructor c) ty = do
684703
Nothing -> throwError . errorMessage . UnknownName . fmap DctorName $ c
685704
Just (_, _, ty1, _) -> do
686705
repl <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty1
687-
elaborate <- subsumes repl ty
688-
return $ TypedValue True (elaborate v) ty
706+
ty' <- introduceSkolemScope ty
707+
elaborate <- subsumes repl ty'
708+
return $ TypedValue True (elaborate v) ty'
689709
check' (Let ds val) ty = do
690710
(ds', val') <- inferLetBinding [] ds val (`check` ty)
691711
return $ TypedValue True (Let ds' val') ty

0 commit comments

Comments
 (0)