@@ -50,7 +50,6 @@ import Language.PureScript.Crash (internalError)
50
50
import Language.PureScript.Environment
51
51
import Language.PureScript.Errors (ErrorMessage (.. ), MultipleErrors , SimpleErrorMessage (.. ), errorMessage , errorMessage' , escalateWarningWhen , internalCompilerError , onErrorMessages , onTypesInErrorMessage , parU )
52
52
import Language.PureScript.Names (pattern ByNullSourcePos , Ident (.. ), ModuleName , Name (.. ), ProperName (.. ), ProperNameType (.. ), Qualified (.. ), QualifiedBy (.. ), byMaybeModuleName , coerceProperName , freshIdent )
53
- import Language.PureScript.Traversals (sndM )
54
53
import Language.PureScript.TypeChecker.Deriving (deriveInstance )
55
54
import Language.PureScript.TypeChecker.Entailment (InstanceContext , newDictionaries , replaceTypeClassDictionaries )
56
55
import Language.PureScript.TypeChecker.Kinds (checkConstraint , checkTypeKind , kindOf , kindOfWithScopedVars , unifyKinds' , unknownsWithKinds )
@@ -369,38 +368,62 @@ infer' (Literal ss (ArrayLiteral vals)) = do
369
368
return $ TypedValue' True (Literal ss (ArrayLiteral ts')) (srcTypeApp tyArray els)
370
369
infer' (Literal ss (ObjectLiteral ps)) = do
371
370
ensureNoDuplicateProperties ps
372
- -- We make a special case for Vars in record labels, since these are the
373
- -- only types of expressions for which 'infer' can return a polymorphic type.
374
- -- They need to be instantiated here.
375
- let shouldInstantiate :: Expr -> Bool
376
- shouldInstantiate Var {} = True
377
- shouldInstantiate (PositionedValue _ _ e) = shouldInstantiate e
378
- shouldInstantiate _ = False
379
-
380
- inferProperty :: (PSString , Expr ) -> m (PSString , (Expr , SourceType ))
381
- inferProperty (name, val) = do
382
- TypedValue' _ val' ty <- infer val
383
- valAndType <- if shouldInstantiate val
384
- then instantiatePolyTypeWithUnknowns val' ty
385
- else pure (val', ty)
386
- pure (name, valAndType)
387
-
388
- toRowListItem (lbl, (_, ty)) = srcRowListItem (Label lbl) ty
389
-
390
- fields <- forM ps inferProperty
391
- let ty = srcTypeApp tyRecord $ rowFromList (map toRowListItem fields, srcKindApp srcREmpty kindType)
392
- return $ TypedValue' True (Literal ss (ObjectLiteral (map (fmap (uncurry (TypedValue True ))) fields))) ty
393
- infer' (ObjectUpdate o ps) = do
371
+ typedFields <- inferProperties ps
372
+ let
373
+ toRowListItem :: (PSString , (Expr , SourceType )) -> RowListItem SourceAnn
374
+ toRowListItem (l, (_, t)) = srcRowListItem (Label l) t
375
+
376
+ recordType :: SourceType
377
+ recordType = srcTypeApp tyRecord $ rowFromList (toRowListItem <$> typedFields, srcKindApp srcREmpty kindType)
378
+
379
+ typedProperties :: [(PSString , Expr )]
380
+ typedProperties = fmap (fmap (uncurry (TypedValue True ))) typedFields
381
+ pure $ TypedValue' True (Literal ss (ObjectLiteral typedProperties)) recordType
382
+ infer' (ObjectUpdate ob ps) = do
394
383
ensureNoDuplicateProperties ps
395
- row <- freshTypeWithKind (kindRow kindType)
396
- typedVals <- zipWith (\ (name, _) t -> (name, t)) ps <$> traverse (infer . snd ) ps
397
- let toRowListItem = uncurry srcRowListItem
398
- let newTys = map (\ (name, TypedValue' _ _ ty) -> (Label name, ty)) typedVals
399
- oldTys <- zip (map (Label . fst ) ps) <$> replicateM (length ps) (freshTypeWithKind kindType)
400
- let oldTy = srcTypeApp tyRecord $ rowFromList (toRowListItem <$> oldTys, row)
401
- o' <- TypedValue True <$> (tvToExpr <$> check o oldTy) <*> pure oldTy
402
- let newVals = map (fmap tvToExpr) typedVals
403
- return $ TypedValue' True (ObjectUpdate o' newVals) $ srcTypeApp tyRecord $ rowFromList (toRowListItem <$> newTys, row)
384
+ -- This "tail" holds all other fields not being updated.
385
+ rowType <- freshTypeWithKind (kindRow kindType)
386
+ let updateLabels = Label . fst <$> ps
387
+ -- Generate unification variables for each field in ps.
388
+ --
389
+ -- Given:
390
+ --
391
+ -- ob { a = 0, b = 0 }
392
+ --
393
+ -- Then:
394
+ --
395
+ -- obTypes = [(a, ?0), (b, ?1)]
396
+ obTypes <- zip updateLabels <$> replicateM (length updateLabels) (freshTypeWithKind kindType)
397
+ let obItems :: [RowListItem SourceAnn ]
398
+ obItems = uncurry srcRowListItem <$> obTypes
399
+ -- Create a record type that contains the unification variables.
400
+ --
401
+ -- obRecordType = Record ( a :: ?0, b :: ?1 | rowType )
402
+ obRecordType :: SourceType
403
+ obRecordType = srcTypeApp tyRecord $ rowFromList (obItems, rowType)
404
+ -- Check ob against obRecordType.
405
+ --
406
+ -- Given:
407
+ --
408
+ -- ob : { a :: Int, b :: Int }
409
+ --
410
+ -- Then:
411
+ --
412
+ -- ?0 ~ Int
413
+ -- ?1 ~ Int
414
+ -- ob' : { a :: ?0, b :: ?1 }
415
+ ob' <- TypedValue True <$> (tvToExpr <$> check ob obRecordType) <*> pure obRecordType
416
+ -- Infer the types of the values used for the record update.
417
+ typedFields <- inferProperties ps
418
+ let newItems :: [RowListItem SourceAnn ]
419
+ newItems = (\ (l, (_, t)) -> srcRowListItem (Label l) t) <$> typedFields
420
+
421
+ ps' :: [(PSString , Expr )]
422
+ ps' = (\ (l, (e, t)) -> (l, TypedValue True e t)) <$> typedFields
423
+
424
+ newRecordType :: SourceType
425
+ newRecordType = srcTypeApp tyRecord $ rowFromList (newItems, rowType)
426
+ pure $ TypedValue' True (ObjectUpdate ob' ps') newRecordType
404
427
infer' (Accessor prop val) = withErrorMessageHint (ErrorCheckingAccessor val prop) $ do
405
428
field <- freshTypeWithKind kindType
406
429
rest <- freshTypeWithKind (kindRow kindType)
@@ -431,8 +454,7 @@ infer' v@(Constructor _ c) = do
431
454
env <- getEnv
432
455
case M. lookup c (dataConstructors env) of
433
456
Nothing -> throwError . errorMessage . UnknownName . fmap DctorName $ c
434
- Just (_, _, ty, _) -> do (v', ty') <- sndM (introduceSkolemScope <=< replaceAllTypeSynonyms) <=< instantiatePolyTypeWithUnknowns v $ ty
435
- return $ TypedValue' True v' ty'
457
+ Just (_, _, ty, _) -> TypedValue' True v <$> (introduceSkolemScope <=< replaceAllTypeSynonyms $ ty)
436
458
infer' (Case vals binders) = do
437
459
(vals', ts) <- instantiateForBinders vals binders
438
460
ret <- freshTypeWithKind kindType
@@ -474,6 +496,44 @@ infer' (PositionedValue pos c val) = warnAndRethrowWithPositionTC pos $ do
474
496
return $ TypedValue' t (PositionedValue pos c v) ty
475
497
infer' v = internalError $ " Invalid argument to infer: " ++ show v
476
498
499
+ -- |
500
+ -- Infer the types of named record fields.
501
+ inferProperties
502
+ :: ( MonadSupply m
503
+ , MonadState CheckState m
504
+ , MonadError MultipleErrors m
505
+ , MonadWriter MultipleErrors m
506
+ )
507
+ => [(PSString , Expr )]
508
+ -> m [(PSString , (Expr , SourceType ))]
509
+ inferProperties = traverse (traverse inferWithinRecord)
510
+
511
+ -- |
512
+ -- Infer the type of a value when used as a record field.
513
+ inferWithinRecord
514
+ :: ( MonadSupply m
515
+ , MonadState CheckState m
516
+ , MonadError MultipleErrors m
517
+ , MonadWriter MultipleErrors m
518
+ )
519
+ => Expr
520
+ -> m (Expr , SourceType )
521
+ inferWithinRecord e = do
522
+ TypedValue' _ v t <- infer e
523
+ if propertyShouldInstantiate e
524
+ then instantiatePolyTypeWithUnknowns v t
525
+ else pure (v, t)
526
+
527
+ -- |
528
+ -- Determines if a value's type needs to be monomorphized when
529
+ -- used inside of a record.
530
+ propertyShouldInstantiate :: Expr -> Bool
531
+ propertyShouldInstantiate = \ case
532
+ Var {} -> True
533
+ Constructor {} -> True
534
+ PositionedValue _ _ e -> propertyShouldInstantiate e
535
+ _ -> False
536
+
477
537
inferLetBinding
478
538
:: (MonadSupply m , MonadState CheckState m , MonadError MultipleErrors m , MonadWriter MultipleErrors m )
479
539
=> [Declaration ]
@@ -795,7 +855,7 @@ check' v@(Constructor _ c) ty = do
795
855
Nothing -> throwError . errorMessage . UnknownName . fmap DctorName $ c
796
856
Just (_, _, ty1, _) -> do
797
857
repl <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty1
798
- ty' <- introduceSkolemScope ty
858
+ ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty
799
859
elaborate <- subsumes repl ty'
800
860
return $ TypedValue' True (elaborate v) ty'
801
861
check' (Let w ds val) ty = do
@@ -841,11 +901,11 @@ checkProperties expr ps row lax = convert <$> go ps (toRowPair <$> ts') r' where
841
901
go ((p,v): ps') ts r =
842
902
case lookup (Label p) ts of
843
903
Nothing -> do
844
- v' @ ( TypedValue' _ _ ty) <- infer v
904
+ (v', ty) <- inferWithinRecord v
845
905
rest <- freshTypeWithKind (kindRow kindType)
846
906
unifyTypes r (srcRCons (Label p) ty rest)
847
907
ps'' <- go ps' ts rest
848
- return $ (p, v' ) : ps''
908
+ return $ (p, TypedValue' True v' ty ) : ps''
849
909
Just ty -> do
850
910
v' <- check v ty
851
911
ps'' <- go ps' (delete (Label p, ty) ts) r
0 commit comments