-
Notifications
You must be signed in to change notification settings - Fork 1
/
TypeCheck.lhs
1415 lines (1278 loc) · 57.8 KB
/
TypeCheck.lhs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
% -*- LaTeX -*-
% $Id: TypeCheck.lhs 3293 2016-08-27 14:42:49Z wlux $
%
% Copyright (c) 1999-2016, Wolfgang Lux
% See LICENSE for the full license.
%
\nwfilename{TypeCheck.lhs}
\section{Type Inference}
This module implements the type checker of the Curry compiler. The
type checker is invoked after the syntactic correctness of the program
has been verified and kind checking has been applied to all type
expressions. Local variables have been renamed already. Therefore, the
compiler can maintain a flat type environment. The type checker now
checks the correct typing of all expressions and also verifies that
the type signatures given by the user match the inferred types. The
type checker uses algorithm W~\cite{DamasMilner82:Principal} for
inferring the types of unannotated declarations, but allows for
polymorphic recursion when a type annotation is present.
The result of type checking is a (flat) top-level environment
containing the types of all constructors, variables, and functions
defined at the top level of a module. In addition, a type annotated
source module or goal is returned. Note that type annotations on the
left hand side of a declaration hold the function or variable's
generalized type with the type scheme's for all qualifier left
implicit. Type annotations on the right hand side of a declaration
hold the particular instance at which a polymorphic function or
variable is used.
\begin{verbatim}
> module TypeCheck(typeCheck,typeCheckGoal) where
> import Applicative()
> import Base
> import Combined
> import Curry
> import CurryPP
> import CurryUtils
> import Env
> import Error
> import List
> import Monad
> import Position
> import PredefIdent
> import PredefTypes
> import Pretty
> import SCC
> import Set
> import TopEnv
> import Types
> import TypeInfo
> import TypeSubst
> import TypeTrans
> import Utils
> import ValueInfo
> infixl 5 $-$
> infixl 1 >>-, >>=-
> ($-$) :: Doc -> Doc -> Doc
> x $-$ y = x $$ text "" $$ y
> (>>-) :: Monad m => m (a,b) -> (a -> m ()) -> m b
> m >>- f =
> do
> (x,y) <- m
> f x
> return y
> (>>=-) :: Monad m => m (a,c) -> (a -> m b) -> m (b,c)
> m >>=- f =
> do
> (x,z) <- m
> y <- f x
> return (y,z)
\end{verbatim}
Before checking the function declarations of a module, the compiler
adds the types of all data and newtype constructors defined in the
current module to the type environment.
\begin{verbatim}
> typeCheck :: ModuleIdent -> TCEnv -> ValueEnv -> [TopDecl a]
> -> Error (ValueEnv,[TopDecl Type])
> typeCheck m tcEnv tyEnv ds = run $
> do
> tds' <- liftSt (liftSt (mapA (tcTopDecl tcEnv) tds))
> (tyEnv'',vds') <- tcDecls m tcEnv tyEnv' [d | BlockDecl d <- vds]
> theta <- fetchSt
> return (subst theta tyEnv'',
> tds' ++ map (BlockDecl . fmap (subst theta)) vds')
> where (vds,tds) = partition isBlockDecl ds
> tyEnv' = foldr (bindConstrs m tcEnv) tyEnv tds
\end{verbatim}
Type checking of a goal is simpler because there are no type
declarations.
\begin{verbatim}
> typeCheckGoal :: ModuleIdent -> TCEnv -> ValueEnv -> Goal a
> -> Error (Goal Type)
> typeCheckGoal m tcEnv tyEnv g = run $
> do
> (_,g') <- tcGoal m tcEnv tyEnv g
> theta <- fetchSt
> return (fmap (subst theta) g')
\end{verbatim}
The type checker makes use of nested state monads in order to maintain
the current substitution and a counter, which is used for generating
fresh type variables.
\begin{verbatim}
> type TcState a = StateT TypeSubst (StateT Int Error) a
> run :: TcState a -> Error a
> run m = callSt (callSt m idSubst) 1
\end{verbatim}
\paragraph{Defining Data Constructors}
First, the types of all data and newtype constructors as well as those
of their field labels are entered into the type environment. All type
synonyms occurring in their types are expanded. We cannot use
\texttt{expandPolyType} for expanding the type of a data or newtype
constructor in function \texttt{bindConstr} because of the different
normalization scheme used for constructor types and also because the
name of the type could be ambiguous.
\begin{verbatim}
> bindConstrs :: ModuleIdent -> TCEnv -> TopDecl a -> ValueEnv -> ValueEnv
> bindConstrs m tcEnv (DataDecl _ tc tvs cs) tyEnv =
> foldr bindCon (foldr (uncurry bindLab) tyEnv (nubBy sameLabel ls)) cs
> where ty0 = constrType m tc tvs
> ls = [(l,ty) | RecordDecl _ _ _ fs <- cs,
> FieldDecl _ ls ty <- fs, l <- ls]
> bindCon (ConstrDecl _ _ c tys) =
> bindConstr m tcEnv tvs c (zip (repeat anonId) tys) ty0
> bindCon (ConOpDecl _ _ ty1 op ty2) =
> bindConstr m tcEnv tvs op [(anonId,ty1),(anonId,ty2)] ty0
> bindCon (RecordDecl _ _ c fs) = bindConstr m tcEnv tvs c tys ty0
> where tys = [(l,ty) | FieldDecl _ ls ty <- fs, l <- ls]
> bindLab = bindLabel m tcEnv tvs ty0
> sameLabel (l1,_) (l2,_) = l1 == l2
> bindConstrs m tcEnv (NewtypeDecl _ tc tvs nc) tyEnv = bind nc tyEnv
> where ty0 = constrType m tc tvs
> bind (NewConstrDecl _ c ty) =
> bindNewConstr m tcEnv tvs c anonId ty ty0
> bind (NewRecordDecl _ c l ty) =
> bindNewConstr m tcEnv tvs c l ty ty0 .
> bindLabel m tcEnv tvs ty0 l ty
> bindConstrs _ _ (TypeDecl _ _ _ _) tyEnv = tyEnv
> bindConstrs _ _ (BlockDecl _) tyEnv = tyEnv
> bindConstr :: ModuleIdent -> TCEnv -> [Ident] -> Ident -> [(Ident,TypeExpr)]
> -> Type -> ValueEnv -> ValueEnv
> bindConstr m tcEnv tvs c tys ty0 =
> globalBindTopEnv m c (DataConstructor (qualifyWith m c) ls ty')
> where ty' = polyType (normalize (length tvs) (foldr TypeArrow ty0 tys''))
> tys'' = expandMonoTypes tcEnv tvs tys'
> (ls,tys') = unzip tys
> bindNewConstr :: ModuleIdent -> TCEnv -> [Ident] -> Ident -> Ident -> TypeExpr
> -> Type -> ValueEnv -> ValueEnv
> bindNewConstr m tcEnv tvs c l ty1 ty0 =
> globalBindTopEnv m c (NewtypeConstructor (qualifyWith m c) l ty')
> where ty' = polyType (normalize (length tvs) (TypeArrow ty1' ty0))
> ty1' = expandMonoType tcEnv tvs ty1
> bindLabel :: ModuleIdent -> TCEnv -> [Ident] -> Type -> Ident -> TypeExpr
> -> ValueEnv -> ValueEnv
> bindLabel m tcEnv tvs ty0 l ty =
> globalBindTopEnv m l (Value (qualifyWith m l) 1 ty')
> where ty' = polyType (TypeArrow ty0 (expandMonoType tcEnv tvs ty))
> constrType :: ModuleIdent -> Ident -> [Ident] -> Type
> constrType m tc tvs =
> TypeConstructor (qualifyWith m tc) (map TypeVariable [0..length tvs-1])
\end{verbatim}
\paragraph{Type Signatures}
The type checker collects type signatures in a flat environment. The
types are not expanded so that the signatures can be used in the error
messages which are printed when an inferred type is less general than
the signature.
\begin{verbatim}
> type SigEnv = Env Ident TypeExpr
> noSigs :: SigEnv
> noSigs = emptyEnv
> bindTypeSigs :: Decl a -> SigEnv -> SigEnv
> bindTypeSigs (TypeSig _ vs ty) env = foldr (flip bindEnv ty) env vs
> bindTypeSigs _ env = env
\end{verbatim}
\paragraph{Top-level Declarations}
When a field label occurs in more than one constructor declaration of
a data type, the compiler ensures that the label is defined
consistently. In addition, the compiler ensures that no existentially
quantified type variable occurs in the type of a field label because
such type variables necessarily escape their scope with the type of
the record selection function associated with the field label.
\begin{verbatim}
> tcTopDecl :: TCEnv -> TopDecl a -> Error (TopDecl Type)
> tcTopDecl tcEnv (DataDecl p tc tvs cs) =
> do
> ls' <- mapA (uncurry (tcFieldLabel tcEnv tvs)) ls
> mapA_ (uncurry tcFieldLabels) (groupLabels ls')
> return (DataDecl p tc tvs cs)
> where ls = [(P p l,ty) | RecordDecl _ _ _ fs <- cs,
> FieldDecl p ls ty <- fs, l <- ls]
> tcTopDecl _ (NewtypeDecl p tc tvs nc) = return (NewtypeDecl p tc tvs nc)
> tcTopDecl _ (TypeDecl p tc tvs ty) = return (TypeDecl p tc tvs ty)
> tcFieldLabel :: TCEnv -> [Ident] -> P Ident -> TypeExpr
> -> Error (P Ident,Type)
> tcFieldLabel tcEnv tvs (P p l) ty
> | n <= length tvs = return (P p l,ty')
> | otherwise = errorAt p (skolemFieldLabel l)
> where ForAll n ty' = polyType (expandMonoType tcEnv tvs ty)
> tcFieldLabels :: P Ident -> [Type] -> Error ()
> tcFieldLabels (P p l) (ty:tys) =
> unless (all (ty ==) tys) (errorAt p (inconsistentFieldLabel l))
> groupLabels :: Eq a => [(a,b)] -> [(a,[b])]
> groupLabels [] = []
> groupLabels ((x,y):xys) = (x,y:map snd xys') : groupLabels xys''
> where (xys',xys'') = partition ((x ==) . fst) xys
\end{verbatim}
\paragraph{Declaration Groups}
Before type checking a group of declarations, a dependency analysis is
performed and the declaration group is split into minimal nested
binding groups which are checked separately. Within each binding
group, first the type environment is extended with new bindings for
all variables and functions defined in the group. Next, types are
inferred for all declarations without an explicit type signature and
the inferred types are then generalized. Finally, the types of all
explicitly typed declarations are checked.
The idea of checking the explicitly typed declarations after the
implicitly typed declarations is due to Mark P.\ Jones' ``Typing
Haskell in Haskell'' paper~\cite{Jones99:THiH}. It has the advantage
of inferring more general types. For instance, given the declarations
\begin{verbatim}
f :: a -> Bool
f x = (x==x) || g True
g y = (y<=y) || f True
\end{verbatim}
the compiler will infer type \texttt{a -> Bool} for \texttt{g} if
\texttt{f} is checked after inferring a type for \texttt{g}, but only
type \texttt{Bool -> Bool} if both declarations are checked together.
The presence of unbound logical variables necessitates a monomorphism
restriction that prohibits unsound functions like
\begin{verbatim}
bug = x =:= 1 & x =:= 'a' where x free
\end{verbatim}
This declaration would be accepted by the type checker if \verb|x|'s
type were generalized to $\forall\alpha.\alpha$. Curry's type system
(cf.\ Sect.~4.2 of~\cite{Hanus:Report}) is presently defined for
programs that have been transformed into a set of global, possibly
mutually recursive function declarations, where local declarations are
used only to introduce logical variables. Under this transformation,
the types of all local variables are monomorphic because the
Hindley-Milner type system does not generalize the types of
lambda-bound variables and logical variables are required to be
monomorphic by the existential rule of Curry's type system.
While sound, Curry's present type system is overly restrictive. Some
perfectly valid declarations like
\begin{verbatim}
ok = (1:nil, 'a':nil) where nil = []
\end{verbatim}
are rejected by the compiler. A safe extension of Curry's type system
would allow polymorphic generalization for variables that are bound to
expressions containing no free variables. Yet, identifying ground
terms in general requires a complex semantic analysis and therefore
should not be a prerequisite for type checking. A good compromise is
to allow polymorphic generalization for variables that are bound to
expressions for which the compiler can easily prove that they do not
contain free variables. The distinction between expansive and
non-expansive expressions comes to help here, which is used with
ML-like languages to ensure type soundness in the presence of
imperative effects~\cite{WrightFelleisen94:TypeSoundness}. In Curry, a
non-expansive expression is either
\begin{itemize}\label{non-expansive}
\item a literal,
\item a bound variable,
\item an application of a data constructor with arity $n$ to $n$
non-expansive expressions,
\item a partial application of a function or constructor with arity
$n$ to $m<n$ non-expansive expressions,
\item a let expression whose body is a non-expansive expression and
whose local declarations are either function declarations or
variable declarations of the form \texttt{$x$=$e$} where $e$ is a
non-expansive expression, or
\item an expression whose desugared form is one of the above.
\end{itemize}
At first it may seem strange that variables are included in the list
above because a variable may be bound to a logical variable. However,
this is no problem because type variables that are present among the
typing assumptions of the environment enclosing a let expression
cannot be generalized.
Recently, Garrigue has shown that ML's value restriction can be lifted
a bit and that generalizing type variables that appear only in
covariant positions is sound~\cite{Garrigue04:ValueRestriction}.
Obviously, this generalization does not hold for Curry with
\texttt{let x = unknown in x} being the canonical counter-example.
Within a group of mutually recursive declarations, all type variables
that appear in the types of the variables defined in the group must
not be generalized. Without this restriction, the compiler would
accept the function
\begin{verbatim}
illTyped = x=:=1 &> f True "Hello"
where (x:xs) = f True (repeat unknown)
f _ [] = []
f b (y:ys) = (if b then y else x) : f (not b) ys
\end{verbatim}
whose result is the ill-typed list \verb|['H',1,'l',1,'o']|,
because \verb|f|'s type would incorrectly be generalized to
$\forall\alpha.\texttt{Bool}\rightarrow[\alpha]\rightarrow[\alpha]$.
\begin{verbatim}
> tcDecls :: ModuleIdent -> TCEnv -> ValueEnv -> [Decl a]
> -> TcState (ValueEnv,[Decl Type])
> tcDecls m tcEnv tyEnv ds =
> do
> (tyEnv',dss') <-
> mapAccumM (tcDeclGroup m tcEnv (foldr bindTypeSigs noSigs ods)) tyEnv
> (scc bv (qfv m) vds)
> return (tyEnv',map untyped ods ++ concat dss')
> where (vds,ods) = partition isValueDecl ds
> tcDeclGroup :: ModuleIdent -> TCEnv -> SigEnv -> ValueEnv -> [Decl a]
> -> TcState (ValueEnv,[Decl Type])
> tcDeclGroup m tcEnv _ tyEnv [ForeignDecl p fi _ f ty] =
> do
> (tyEnv',ty') <- tcForeignFunct m tcEnv tyEnv p fi f ty
> return (tyEnv',[ForeignDecl p fi ty' f ty])
> tcDeclGroup m tcEnv sigs tyEnv [FreeDecl p vs] =
> do
> vs' <- mapM (tcDeclVar False tcEnv sigs p) (bv vs)
> return (bindVars m tyEnv vs',[FreeDecl p (map freeVar vs')])
> where freeVar (v,_,ty) = FreeVar (rawType ty) v
> tcDeclGroup m tcEnv sigs tyEnv ds =
> do
> vss <- mapM (tcDeclVars tcEnv sigs) ds
> let tyEnv' = bindVars m tyEnv (concat vss)
> impDs' <- mapM (tcDecl m tcEnv tyEnv') impDs
> theta <- fetchSt
> let tvs =
> [tv | (ty,d) <- impDs', not (isNonExpansive tcEnv tyEnv' d),
> tv <- typeVars (subst theta ty)]
> fvs = foldr addToSet (fvEnv (subst theta tyEnv)) tvs
> let impDs'' = map (uncurry (fixType . gen fvs . subst theta)) impDs'
> tyEnv'' = rebindVars m tyEnv' (concatMap declVars impDs'')
> expDs' <- mapM (uncurry (tcCheckDecl m tcEnv tyEnv'')) expDs
> return (tyEnv'',impDs'' ++ expDs')
> where (impDs,expDs) = partDecls sigs ds
> partDecls :: SigEnv -> [Decl a] -> ([Decl a],[(TypeExpr,Decl a)])
> partDecls sigs =
> foldr (\d -> maybe (implicit d) (explicit d) (declTypeSig sigs d)) ([],[])
> where implicit d ~(impDs,expDs) = (d:impDs,expDs)
> explicit d ty ~(impDs,expDs) = (impDs,(ty,d):expDs)
> declTypeSig :: SigEnv -> Decl a -> Maybe TypeExpr
> declTypeSig sigs (FunctionDecl _ _ f _) = lookupEnv f sigs
> declTypeSig sigs (PatternDecl _ t _) =
> case t of
> VariablePattern _ v -> lookupEnv v sigs
> _ -> Nothing
> bindVars :: ModuleIdent -> ValueEnv -> [(Ident,Int,TypeScheme)] -> ValueEnv
> bindVars m = foldr (uncurry3 (bindFun m))
> rebindVars :: ModuleIdent -> ValueEnv -> [(Ident,Int,TypeScheme)] -> ValueEnv
> rebindVars m = foldr (uncurry3 (rebindFun m))
> tcDeclVars :: TCEnv -> SigEnv -> Decl a -> TcState [(Ident,Int,TypeScheme)]
> tcDeclVars tcEnv sigs (FunctionDecl _ _ f eqs) =
> case lookupEnv f sigs of
> Just ty -> return [(f,n,expandPolyType tcEnv ty)]
> Nothing ->
> do
> tys <- replicateM (n + 1) freshTypeVar
> return [(f,n,monoType (foldr1 TypeArrow tys))]
> where n = eqnArity (head eqs)
> tcDeclVars tcEnv sigs (PatternDecl p t _) =
> case t of
> VariablePattern _ v -> mapM (tcDeclVar True tcEnv sigs p) [v]
> _ -> mapM (tcDeclVar False tcEnv sigs p) (bv t)
> tcDeclVar :: Bool -> TCEnv -> SigEnv -> Position -> Ident
> -> TcState (Ident,Int,TypeScheme)
> tcDeclVar poly tcEnv sigs p v =
> case lookupEnv v sigs of
> Just ty
> | poly || null (fv ty) -> return (v,0,expandPolyType tcEnv ty)
> | otherwise -> errorAt p (polymorphicVar v)
> Nothing -> lambdaVar v
> tcDecl :: ModuleIdent -> TCEnv -> ValueEnv -> Decl a
> -> TcState (Type,Decl Type)
> tcDecl m tcEnv tyEnv (FunctionDecl p _ f eqs) =
> do
> theta <- fetchSt
> ty <- inst (varType f tyEnv)
> eqs' <-
> mapM (tcEquation m tcEnv tyEnv (fsEnv (subst theta tyEnv)) ty f) eqs
> return (ty,FunctionDecl p ty f eqs')
> tcDecl m tcEnv tyEnv d@(PatternDecl p t rhs) =
> do
> (ty,t') <- tcConstrTerm tcEnv tyEnv p t
> rhs' <-
> tcRhs m tcEnv tyEnv rhs >>-
> unify p "pattern declaration" (ppDecl d) tcEnv ty
> return (ty,PatternDecl p t' rhs')
> tcEquation :: ModuleIdent -> TCEnv -> ValueEnv -> Set Int -> Type -> Ident
> -> Equation a -> TcState (Equation Type)
> tcEquation m tcEnv tyEnv fs ty f eq@(Equation p lhs rhs) =
> tcEqn m tcEnv tyEnv fs p lhs rhs >>-
> unify p "equation" (ppEquation eq) tcEnv ty
> tcEqn :: ModuleIdent -> TCEnv -> ValueEnv -> Set Int -> Position
> -> Lhs a -> Rhs a -> TcState (Type,Equation Type)
> tcEqn m tcEnv tyEnv fs p lhs rhs =
> do
> tyEnv' <- bindLambdaVars m tyEnv lhs
> (tys,lhs') <- tcLhs tcEnv tyEnv' p lhs
> (ty,rhs') <- tcRhs m tcEnv tyEnv' rhs
> checkSkolems p "Equation" ppEquation tcEnv tyEnv fs
> (foldr TypeArrow ty tys) (Equation p lhs' rhs')
> bindLambdaVars :: QuantExpr t => ModuleIdent -> ValueEnv -> t
> -> TcState ValueEnv
> bindLambdaVars m tyEnv t = liftM (bindVars m tyEnv) (mapM lambdaVar (bv t))
> lambdaVar :: Ident -> TcState (Ident,Int,TypeScheme)
> lambdaVar v = freshTypeVar >>= \ty -> return (v,0,monoType ty)
> tcGoal :: ModuleIdent -> TCEnv -> ValueEnv -> Goal a
> -> TcState (Type,Goal Type)
> tcGoal m tcEnv tyEnv (Goal p e ds) =
> do
> (tyEnv',ds') <- tcDecls m tcEnv tyEnv ds
> (ty,e') <- tcExpr m tcEnv tyEnv' p e
> checkSkolems p "Goal" ppGoal tcEnv tyEnv zeroSet ty (Goal p e' ds')
\end{verbatim}
After \texttt{tcDeclGroup} has generalized the types of the implicitly
typed declarations of a declaration group it must update their left
hand side type annotations and the type environment accordingly.
Recall that the compiler generalizes only the types of variable and
function declarations.
\begin{verbatim}
> fixType :: TypeScheme -> Decl Type -> Decl Type
> fixType ty (FunctionDecl p _ f eqs) = FunctionDecl p (rawType ty) f eqs
> fixType ty (PatternDecl p t rhs) = PatternDecl p (fixVarType ty t) rhs
> where fixVarType ty t =
> case t of
> VariablePattern _ v -> VariablePattern (rawType ty) v
> _ -> t
> declVars :: Decl Type -> [(Ident,Int,TypeScheme)]
> declVars (FunctionDecl _ ty f eqs) = [(f,eqnArity (head eqs),polyType ty)]
> declVars (PatternDecl _ t _) =
> case t of
> VariablePattern ty v -> [(v,0,polyType ty)]
> _ -> []
\end{verbatim}
The function \texttt{tcCheckDecl} checks the type of an explicitly
typed function or variable declaration. After inferring a type for the
declaration, the inferred type is compared with the type signature.
Since the inferred type of an explicitly typed function or variable
declaration is automatically an instance of its type signature (cf.\
\texttt{tcDecl} above), the type signature is correct only if the
inferred type matches the type signature exactly.
\begin{verbatim}
> tcCheckDecl :: ModuleIdent -> TCEnv -> ValueEnv -> TypeExpr -> Decl a
> -> TcState (Decl Type)
> tcCheckDecl m tcEnv tyEnv sigTy d =
> do
> (ty,d') <- tcDecl m tcEnv tyEnv d
> theta <- fetchSt
> let fvs = fvEnv (subst theta tyEnv)
> ty' = subst theta ty
> checkDeclSig tcEnv sigTy (if poly then gen fvs ty' else monoType ty') d'
> where poly = isNonExpansive tcEnv tyEnv d
> checkDeclSig :: TCEnv -> TypeExpr -> TypeScheme -> Decl Type
> -> TcState (Decl Type)
> checkDeclSig tcEnv sigTy sigma (FunctionDecl p _ f eqs)
> | sigma == expandPolyType tcEnv sigTy =
> return (FunctionDecl p (rawType sigma) f eqs)
> | otherwise = errorAt p (typeSigTooGeneral tcEnv what sigTy sigma)
> where what = text "Function:" <+> ppIdent f
> checkDeclSig tcEnv sigTy sigma (PatternDecl p (VariablePattern _ v) rhs)
> | sigma == expandPolyType tcEnv sigTy =
> return (PatternDecl p (VariablePattern (rawType sigma) v) rhs)
> | otherwise = errorAt p (typeSigTooGeneral tcEnv what sigTy sigma)
> where what = text "Variable:" <+> ppIdent v
> class Binding a where
> isNonExpansive :: TCEnv -> ValueEnv -> a -> Bool
> instance Binding a => Binding [a] where
> isNonExpansive tcEnv tyEnv = all (isNonExpansive tcEnv tyEnv)
> instance Binding (Decl a) where
> isNonExpansive _ _ (InfixDecl _ _ _ _) = True
> isNonExpansive _ _ (TypeSig _ _ _) = True
> isNonExpansive _ _ (FunctionDecl _ _ _ _) = True
> isNonExpansive _ _ (ForeignDecl _ _ _ _ _) = True
> isNonExpansive tcEnv tyEnv (PatternDecl _ t rhs) =
> isVariablePattern t && isNonExpansive tcEnv tyEnv rhs
> isNonExpansive _ _ (FreeDecl _ _) = False
> isNonExpansive _ _ (TrustAnnot _ _ _) = True
> instance Binding (Rhs a) where
> isNonExpansive tcEnv tyEnv (SimpleRhs _ e ds) =
> isNonExpansive tcEnv tyEnv' ds && isNonExpansive tcEnv tyEnv' e
> where tyEnv' = foldr (bindDeclArity tcEnv) tyEnv ds
> isNonExpansive _ _ (GuardedRhs _ _) = False
> instance Binding (Expression a) where
> isNonExpansive tcEnv tyEnv = isNonExpansiveApp tcEnv tyEnv 0
> instance Binding a => Binding (Field a) where
> isNonExpansive tcEnv tyEnv (Field _ e) = isNonExpansive tcEnv tyEnv e
> isNonExpansiveApp :: TCEnv -> ValueEnv -> Int -> Expression a -> Bool
> isNonExpansiveApp _ _ _ (Literal _ _) = True
> isNonExpansiveApp _ tyEnv n (Variable _ v)
> | unRenameIdent (unqualify v) == anonId = False
> | isRenamed (unqualify v) = n == 0 || n < arity v tyEnv
> | otherwise = n < arity v tyEnv
> isNonExpansiveApp _ _ _ (Constructor _ _) = True
> isNonExpansiveApp tcEnv tyEnv n (Paren e) = isNonExpansiveApp tcEnv tyEnv n e
> isNonExpansiveApp tcEnv tyEnv n (Typed e _) =
> isNonExpansiveApp tcEnv tyEnv n e
> isNonExpansiveApp tcEnv tyEnv _ (Record _ c fs) =
> arity c tyEnv == length fs && isNonExpansive tcEnv tyEnv fs
> isNonExpansiveApp tcEnv tyEnv _ (Tuple es) = isNonExpansive tcEnv tyEnv es
> isNonExpansiveApp tcEnv tyEnv _ (List _ es) = isNonExpansive tcEnv tyEnv es
> isNonExpansiveApp tcEnv tyEnv n (Apply f e) =
> isNonExpansiveApp tcEnv tyEnv (n + 1) f && isNonExpansive tcEnv tyEnv e
> isNonExpansiveApp tcEnv tyEnv n (InfixApply e1 op e2) =
> isNonExpansiveApp tcEnv tyEnv (n + 2) (infixOp op) &&
> isNonExpansive tcEnv tyEnv e1 && isNonExpansive tcEnv tyEnv e2
> isNonExpansiveApp tcEnv tyEnv n (LeftSection e op) =
> isNonExpansiveApp tcEnv tyEnv (n + 1) (infixOp op) &&
> isNonExpansive tcEnv tyEnv e
> isNonExpansiveApp tcEnv tyEnv n (Lambda _ ts e) =
> n < length ts ||
> all isVarPattern ts && isNonExpansiveApp tcEnv tyEnv' (n - length ts) e
> where tyEnv' = foldr bindVarArity tyEnv (bv ts)
> isNonExpansiveApp tcEnv tyEnv n (Let ds e) =
> isNonExpansive tcEnv tyEnv' ds && isNonExpansiveApp tcEnv tyEnv' n e
> where tyEnv' = foldr (bindDeclArity tcEnv) tyEnv ds
> isNonExpansiveApp _ _ _ _ = False
> bindDeclArity :: TCEnv -> Decl a -> ValueEnv -> ValueEnv
> bindDeclArity _ (InfixDecl _ _ _ _) tyEnv = tyEnv
> bindDeclArity _ (TypeSig _ _ _) tyEnv = tyEnv
> bindDeclArity _ (FunctionDecl _ _ f eqs) tyEnv =
> bindArity f (eqnArity (head eqs)) tyEnv
> bindDeclArity tcEnv (ForeignDecl _ _ _ f ty) tyEnv =
> bindArity f (foreignArity (rawType (expandPolyType tcEnv ty))) tyEnv
> bindDeclArity _ (PatternDecl _ t _) tyEnv = foldr bindVarArity tyEnv (bv t)
> bindDeclArity _ (FreeDecl _ vs) tyEnv = foldr bindVarArity tyEnv (bv vs)
> bindDeclArity _ (TrustAnnot _ _ _) tyEnv = tyEnv
> bindVarArity :: Ident -> ValueEnv -> ValueEnv
> bindVarArity v tyEnv = bindArity v 0 tyEnv
> bindArity :: Ident -> Int -> ValueEnv -> ValueEnv
> bindArity v n tyEnv = localBindTopEnv v (Value (qualify v) n undefined) tyEnv
\end{verbatim}
\paragraph{Foreign Functions}
According to the Haskell foreign function interface
specification~\cite{Chakravarty03:FFI}, argument and result types of
foreign functions using the \texttt{ccall} calling convention must be
marshalable foreign types and marshalable foreign result types,
respectively. A marshalable foreign type is either
\begin{itemize}
\item one of the basic types \texttt{Bool}, \texttt{Char},
\texttt{Int}, \texttt{Float}, \texttt{Ptr}, \texttt{FunPtr}, and
\texttt{StablePtr},\footnote{The Haskell FFI specification knows
about more basic types, but these are not yet available in Curry.}
\item a type $T\,t'_1\,\dots\,t'_n$ where $T$ is defined as a type
synomym
%\begin{quote}
\texttt{type $T\,a_1\,\dots\,a_n$ = $t$}
%\end{quote}
and the type $t[a_1/t'_1,\dots,a_n/t'_n]$ is a marshalable foreign type, or
\item a type $T\,t'_1\,\dots\,t'_n$ where $T$ is defined as a renaming
type
%\begin{quote}
\texttt{newtype $T\,a_1\,\dots\,a_n$ = $N$ $t$},
%\end{quote}
the type $t[a_1/t'_1,\dots,a_n/t'_n]$ is a marshalable foreign type, and
the constructor $N$ is visible.
\end{itemize}
A marshalable foreign result type is either
\begin{itemize}
\item a marshalable foreign type,
\item the type \texttt{()},
\item a type of the form $\texttt{IO}\;t$ where $t$ is a marshalable
foreign type or \texttt{()},
\item a type $T\,t'_1\,\dots\,t'_n$ where $T$ is defined as a type
synomym
%\begin{quote}
\texttt{type $T\,a_1\,\dots\,a_n$ = $t$}
%\end{quote}
and the type $t[a_1/t'_1,\dots,a_n/t'_n]$ is a marshalable foreign result
type, or
\item a type $T\,t'_1\,\dots\,t'_n$ where $T$ is defined as a renaming
type
%\begin{quote}
\texttt{newtype $T\,a_1\,\dots\,a_n$ = $N$ $t$},
%\end{quote}
the type $t[a_1/t'_1,\dots,a_n/t'_n]$ is a marshalable foreign result
type, and the constructor $N$ is visible.
\end{itemize}
As an extension to the Haskell foreign function interface
specification~\cite{Chakravarty03:FFI}, the compiler supports the
non-standard \texttt{rawcall} calling convention, which allows
arbitrary argument and result types. However, in contrast to the
\texttt{ccall} calling convention, no marshaling takes place at all
even for the basic types (cf.\ Sect.~\ref{sec:il-compile} with regard
to marshaling). The type of a dynamic function wrapper is restricted
further to be of the form $\texttt{FunPtr}\;t \rightarrow t$, where
$t$ is a valid foreign function type, and the type of a foreign
address must be either $\texttt{Ptr}\;a$ or $\texttt{FunPtr}\;a$,
where $a$ is an arbitrary type.
To detect valid foreign (result) types, the compiler must expand type
synonyms and the right hand sides of renaming types in the types used
in a foreign function declaration. For type synonyms this happens
automatically when a source code type expression is converted into the
internal type representation. To expand renaming types, the compiler
collects all visible newtype constructors from the type environment
and creates a new environment mapping the respective type constructors
to their right hand side types. Expansion is complicated by the fact
that renaming types can be (mutually) recursive and thus expansion of
a renaming type may not terminate. To avoid non-termination, the
compiler uses the function \texttt{typeExpansions} to generate a
finite list of successive expansions of a type and checks for the
first type that is a valid foreign (result) type in that list. Note
that the compiler checks each type in the list rather than only the
last one because this avoids generating the auxiliary environment at
all when a basic type or a type synonym of a basic type is used.
Note that a foreign function with type $t_1 \rightarrow \dots
\rightarrow t_n \rightarrow t$ has arity $n$ unless the result type
$t$ is $\texttt{IO}\;t'$, in which case its arity will be $n+1$. This
special case reflects the fact that the type $\texttt{IO}\;t$ is
equivalent to $\emph{World}\rightarrow(t,\emph{World})$.
\begin{verbatim}
> tcForeignFunct :: ModuleIdent -> TCEnv -> ValueEnv
> -> Position -> ForeignImport -> Ident -> TypeExpr
> -> TcState (ValueEnv,Type)
> tcForeignFunct m tcEnv tyEnv p (cc,_,ie) f ty =
> do
> checkForeignType cc (renamingTypes tyEnv) ty'
> return (bindFun m f (foreignArity ty') (ForAll n ty') tyEnv,ty')
> where ForAll n ty' = expandPolyType tcEnv ty
> checkForeignType cc nts ty
> | cc == CallConvPrimitive = return ()
> | ie == Just "dynamic" = checkCDynCallType tcEnv nts p cc ty
> | maybe False ('&' `elem`) ie = checkCAddrType tcEnv p ty
> | otherwise = checkCCallType tcEnv nts p cc ty
> type NewtypeEnv = Env QualIdent Type
> renamingTypes :: ValueEnv -> NewtypeEnv
> renamingTypes tyEnv = foldr bindRenamingType emptyEnv (allEntities tyEnv)
> where bindRenamingType (DataConstructor _ _ _) = id
> bindRenamingType (NewtypeConstructor _ _ ty) = bindType (rawType ty)
> bindRenamingType (Value _ _ _) = id
> bindType (TypeArrow ty (TypeConstructor tc _)) = bindEnv tc ty
> renamedType :: NewtypeEnv -> QualIdent -> Maybe Type
> renamedType nts tc = lookupEnv tc nts
> checkCCallType :: TCEnv -> NewtypeEnv -> Position -> CallConv -> Type
> -> TcState ()
> checkCCallType tcEnv nts p CallConvCCall (TypeArrow ty1 ty2)
> | any isCArgType (typeExpansions (renamedType nts) ty1) =
> checkCCallType tcEnv nts p CallConvCCall ty2
> | otherwise = errorAt p (invalidCType "argument" tcEnv ty1)
> checkCCallType tcEnv nts p CallConvCCall ty
> | any (isCRetType nts) (typeExpansions (renamedType nts) ty) = return ()
> | otherwise = errorAt p (invalidCType "result" tcEnv ty)
> checkCCallType _ _ _ CallConvRawCall _ = return ()
> checkCDynCallType :: TCEnv -> NewtypeEnv -> Position -> CallConv -> Type
> -> TcState ()
> checkCDynCallType tcEnv nts p cc (TypeArrow (TypeConstructor tc [ty1]) ty2)
> | tc == qFunPtrId && ty1 == ty2 = checkCCallType tcEnv nts p cc ty1
> checkCDynCallType tcEnv _ p _ ty =
> errorAt p (invalidCType "dynamic function" tcEnv ty)
> checkCAddrType :: TCEnv -> Position -> Type -> TcState ()
> checkCAddrType tcEnv p ty
> | isCPtrType ty = return ()
> | otherwise = errorAt p (invalidCType "static address" tcEnv ty)
> isCArgType :: Type -> Bool
> isCArgType (TypeConstructor tc []) = tc `elem` cBasicTypeId
> isCArgType (TypeConstructor tc [_]) = tc `elem` qStablePtrId:cPointerTypeId
> isCArgType _ = False
> isCRetType :: NewtypeEnv -> Type -> Bool
> isCRetType _ (TypeConstructor tc [])
> | tc == qUnitId = True
> isCRetType nts (TypeConstructor tc [ty])
> | tc == qIOId =
> ty == unitType || any isCArgType (typeExpansions (renamedType nts) ty)
> isCRetType _ ty = isCArgType ty
> isCPtrType :: Type -> Bool
> isCPtrType (TypeConstructor tc [_]) = tc `elem` cPointerTypeId
> isCPtrType _ = False
> cBasicTypeId, cPointerTypeId :: [QualIdent]
> cBasicTypeId = [qBoolId,qCharId,qIntId,qFloatId]
> cPointerTypeId = [qPtrId,qFunPtrId]
\end{verbatim}
\paragraph{Patterns and Expressions}
Note that the type attribute associated with a constructor or infix
pattern is the type of the whole pattern and not the type of the
constructor itself.
\begin{verbatim}
> tcLiteral :: Literal -> TcState Type
> tcLiteral (Char _) = return charType
> tcLiteral (Int _) = freshConstrained [intType,floatType]
> tcLiteral (Float _) = return floatType
> tcLiteral (String _) = return stringType
> tcLhs :: TCEnv -> ValueEnv -> Position -> Lhs a -> TcState ([Type],Lhs Type)
> tcLhs tcEnv tyEnv p (FunLhs f ts) =
> do
> (tys,ts') <- liftM unzip $ mapM (tcConstrTerm tcEnv tyEnv p) ts
> return (tys,FunLhs f ts')
> tcLhs tcEnv tyEnv p (OpLhs t1 op t2) =
> do
> (ty1,t1') <- tcConstrTerm tcEnv tyEnv p t1
> (ty2,t2') <- tcConstrTerm tcEnv tyEnv p t2
> return ([ty1,ty2],OpLhs t1' op t2')
> tcLhs tcEnv tyEnv p (ApLhs lhs ts) =
> do
> (tys1,lhs') <- tcLhs tcEnv tyEnv p lhs
> (tys2,ts') <- liftM unzip $ mapM (tcConstrTerm tcEnv tyEnv p) ts
> return (tys1 ++ tys2,ApLhs lhs' ts')
> tcConstrTerm :: TCEnv -> ValueEnv -> Position -> ConstrTerm a
> -> TcState (Type,ConstrTerm Type)
> tcConstrTerm _ _ _ (LiteralPattern _ l) =
> do
> ty <- tcLiteral l
> return (ty,LiteralPattern ty l)
> tcConstrTerm _ _ _ (NegativePattern _ op l) =
> do
> ty <- tcLiteral l
> return (ty,NegativePattern ty op l)
> tcConstrTerm _ tyEnv _ (VariablePattern _ v) =
> do
> ty <- inst (varType v tyEnv)
> return (ty,VariablePattern ty v)
> tcConstrTerm tcEnv tyEnv p t@(ConstructorPattern _ c ts) =
> do
> ty <- skol (snd (conType c tyEnv))
> tcConstrApp tcEnv tyEnv p (ppConstrTerm 0 t) c ty ts
> tcConstrTerm tcEnv tyEnv p t@(FunctionPattern _ f ts) =
> do
> ty <- inst (funType f tyEnv)
> tcFunctPattern tcEnv tyEnv p (ppConstrTerm 0 t) f id ty ts
> tcConstrTerm tcEnv tyEnv p t@(InfixPattern _ t1 op t2) =
> do
> ty <- tcPatternOp tyEnv p op
> (alpha,beta,gamma) <-
> tcBinary p "infix pattern" (doc $-$ text "Operator:" <+> ppOp op)
> tcEnv ty
> t1' <- tcConstrArg tcEnv tyEnv p "pattern" doc alpha t1
> t2' <- tcConstrArg tcEnv tyEnv p "pattern" doc beta t2
> return (gamma,InfixPattern gamma t1' op t2')
> where doc = ppConstrTerm 0 t
> tcConstrTerm tcEnv tyEnv p (ParenPattern t) =
> do
> (ty,t') <- tcConstrTerm tcEnv tyEnv p t
> return (ty,ParenPattern t')
> tcConstrTerm tcEnv tyEnv p t@(RecordPattern _ c fs) =
> do
> ty <- liftM arrowBase (skol (snd (conType c tyEnv)))
> fs' <- mapM (tcField tcConstrTerm "pattern" doc tcEnv tyEnv p ty) fs
> return (ty,RecordPattern ty c fs')
> where doc t1 = ppConstrTerm 0 t $-$ text "Term:" <+> ppConstrTerm 0 t1
> tcConstrTerm tcEnv tyEnv p (TuplePattern ts) =
> do
> (tys,ts') <- liftM unzip $ mapM (tcConstrTerm tcEnv tyEnv p) ts
> return (tupleType tys,TuplePattern ts')
> tcConstrTerm tcEnv tyEnv p t@(ListPattern _ ts) =
> do
> ty <- freshTypeVar
> ts' <- mapM (tcConstrArg tcEnv tyEnv p "pattern" (ppConstrTerm 0 t) ty) ts
> return (listType ty,ListPattern (listType ty) ts')
> tcConstrTerm tcEnv tyEnv p t@(AsPattern v t') =
> do
> ty <- inst (varType v tyEnv)
> t'' <-
> tcConstrTerm tcEnv tyEnv p t' >>-
> unify p "pattern" (ppConstrTerm 0 t) tcEnv ty
> return (ty,AsPattern v t'')
> tcConstrTerm tcEnv tyEnv p (LazyPattern t) =
> do
> (ty,t') <- tcConstrTerm tcEnv tyEnv p t
> return (ty,LazyPattern t')
> tcConstrApp :: TCEnv -> ValueEnv -> Position -> Doc -> QualIdent -> Type
> -> [ConstrTerm a] -> TcState (Type,ConstrTerm Type)
> tcConstrApp tcEnv tyEnv p doc c ty ts =
> do
> unless (length tys == n) (errorAt p (wrongArity c (length tys) n))
> ts' <- zipWithM (tcConstrArg tcEnv tyEnv p "pattern" doc) tys ts
> return (ty',ConstructorPattern ty' c ts')
> where (tys,ty') = arrowUnapply ty
> n = length ts
> tcFunctPattern :: TCEnv -> ValueEnv -> Position -> Doc -> QualIdent
> -> ([ConstrTerm Type] -> [ConstrTerm Type]) -> Type
> -> [ConstrTerm a] -> TcState (Type,ConstrTerm Type)
> tcFunctPattern _ _ _ _ f ts ty [] = return (ty,FunctionPattern ty f (ts []))
> tcFunctPattern tcEnv tyEnv p doc f ts ty (t':ts') =
> do
> (alpha,beta) <-
> tcArrow p "pattern" (doc $-$ text "Term:" <+> ppConstrTerm 0 t) tcEnv ty
> t'' <- tcConstrArg tcEnv tyEnv p "pattern" doc alpha t'
> tcFunctPattern tcEnv tyEnv p doc f (ts . (t'':)) beta ts'
> where t = FunctionPattern ty f (ts [])
> tcConstrArg :: TCEnv -> ValueEnv -> Position -> String -> Doc -> Type
> -> ConstrTerm a -> TcState (ConstrTerm Type)
> tcConstrArg tcEnv tyEnv p what doc ty t =
> tcConstrTerm tcEnv tyEnv p t >>-
> unify p what (doc $-$ text "Term:" <+> ppConstrTerm 0 t) tcEnv ty
> tcPatternOp :: ValueEnv -> Position -> InfixOp a -> TcState Type
> tcPatternOp tyEnv p (InfixConstr _ op) =
> do
> ty <- skol (snd (conType op tyEnv))
> unless (arrowArity ty == 2) (errorAt p (wrongArity op (arrowArity ty) 2))
> return ty
> tcPatternOp tyEnv _ (InfixOp _ op) = inst (funType op tyEnv)
> tcRhs :: ModuleIdent -> TCEnv -> ValueEnv -> Rhs a -> TcState (Type,Rhs Type)
> tcRhs m tcEnv tyEnv (SimpleRhs p e ds) =
> do
> (tyEnv',ds') <- tcDecls m tcEnv tyEnv ds
> (ty,e') <- tcExpr m tcEnv tyEnv' p e
> return (ty,SimpleRhs p e' ds')
> tcRhs m tcEnv tyEnv (GuardedRhs es ds) =
> do
> (tyEnv',ds') <- tcDecls m tcEnv tyEnv ds
> ty <- freshTypeVar
> es' <- mapM (tcCondExpr m tcEnv tyEnv' ty) es
> return (ty,GuardedRhs es' ds')
> tcCondExpr :: ModuleIdent -> TCEnv -> ValueEnv -> Type -> CondExpr a
> -> TcState (CondExpr Type)
> tcCondExpr m tcEnv tyEnv ty (CondExpr p g e) =
> do
> g' <-
> tcExpr m tcEnv tyEnv p g >>- unify p "guard" (ppExpr 0 g) tcEnv boolType
> e' <-
> tcExpr m tcEnv tyEnv p e >>- unify p "expression" (ppExpr 0 e) tcEnv ty
> return (CondExpr p g' e')
> tcExpr :: ModuleIdent -> TCEnv -> ValueEnv -> Position -> Expression a
> -> TcState (Type,Expression Type)
> tcExpr _ _ _ _ (Literal _ l) =
> do
> ty <- tcLiteral l
> return (ty,Literal ty l)
> tcExpr _ _ tyEnv _ (Variable _ v) =
> do
> ty <- if unRenameIdent (unqualify v) == anonId then freshTypeVar
> else inst (funType v tyEnv)
> return (ty,Variable ty v)
> tcExpr _ _ tyEnv _ (Constructor _ c) =
> do
> ty <- inst (snd (conType c tyEnv))
> return (ty,Constructor ty c)
> tcExpr m tcEnv tyEnv p (Typed e sig) =
> do
> ty <- inst sigma'
> e' <-
> tcExpr m tcEnv tyEnv p e >>-
> unify p "explicitly typed expression" (ppExpr 0 e) tcEnv ty
> theta <- fetchSt
> let sigma = gen (fvEnv (subst theta tyEnv)) (subst theta ty)
> unless (sigma == sigma')
> (errorAt p (typeSigTooGeneral tcEnv (text "Expression:" <+> ppExpr 0 e)
> sig sigma))
> return (ty,Typed e' sig)
> where sigma' = expandPolyType tcEnv sig
> tcExpr m tcEnv tyEnv p (Paren e) =
> do
> (ty,e') <- tcExpr m tcEnv tyEnv p e
> return (ty,Paren e')
> tcExpr m tcEnv tyEnv p e@(Record _ c fs) =
> do
> ty <- liftM arrowBase (inst (snd (conType c tyEnv)))
> fs' <- mapM (tcField (tcExpr m) "construction" doc tcEnv tyEnv p ty) fs
> return (ty,Record ty c fs')
> where doc e1 = ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1
> tcExpr m tcEnv tyEnv p e@(RecordUpdate e1 fs) =
> do
> (ty,e1') <- tcExpr m tcEnv tyEnv p e1
> fs' <- mapM (tcField (tcExpr m) "update" doc tcEnv tyEnv p ty) fs
> return (ty,RecordUpdate e1' fs')
> where doc e1 = ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1
> tcExpr m tcEnv tyEnv p (Tuple es) =
> do
> (tys,es') <- liftM unzip $ mapM (tcExpr m tcEnv tyEnv p) es
> return (tupleType tys,Tuple es')
> tcExpr m tcEnv tyEnv p e@(List _ es) =
> do
> ty <- freshTypeVar
> es' <- mapM (tcArg m tcEnv tyEnv p "expression" (ppExpr 0 e) ty) es
> return (listType ty,List (listType ty) es')
> tcExpr m tcEnv tyEnv p (ListCompr e qs) =
> do
> fs <- liftM (fsEnv . flip subst tyEnv) fetchSt
> (tyEnv',qs') <- mapAccumM (flip (tcQual m tcEnv) p) tyEnv qs
> (ty,e') <- tcExpr m tcEnv tyEnv' p e
> checkSkolems p "Expression" (ppExpr 0) tcEnv tyEnv fs
> (listType ty) (ListCompr e' qs')
> tcExpr m tcEnv tyEnv p e@(EnumFrom e1) =
> do
> e1' <- tcArg m tcEnv tyEnv p "arithmetic sequence" (ppExpr 0 e) intType e1
> return (listType intType,EnumFrom e1')
> tcExpr m tcEnv tyEnv p e@(EnumFromThen e1 e2) =
> do
> e1' <- tcArg m tcEnv tyEnv p "arithmetic sequence" (ppExpr 0 e) intType e1
> e2' <- tcArg m tcEnv tyEnv p "arithmetic sequence" (ppExpr 0 e) intType e2
> return (listType intType,EnumFromThen e1' e2')
> tcExpr m tcEnv tyEnv p e@(EnumFromTo e1 e2) =
> do
> e1' <- tcArg m tcEnv tyEnv p "arithmetic sequence" (ppExpr 0 e) intType e1
> e2' <- tcArg m tcEnv tyEnv p "arithmetic sequence" (ppExpr 0 e) intType e2
> return (listType intType,EnumFromTo e1' e2')
> tcExpr m tcEnv tyEnv p e@(EnumFromThenTo e1 e2 e3) =
> do
> e1' <- tcArg m tcEnv tyEnv p "arithmetic sequence" (ppExpr 0 e) intType e1
> e2' <- tcArg m tcEnv tyEnv p "arithmetic sequence" (ppExpr 0 e) intType e2
> e3' <- tcArg m tcEnv tyEnv p "arithmetic sequence" (ppExpr 0 e) intType e3
> return (listType intType,EnumFromThenTo e1' e2' e3')
> tcExpr m tcEnv tyEnv p e@(UnaryMinus op e1) =
> do
> ty <- opType op
> e1' <- tcArg m tcEnv tyEnv p "unary negation" (ppExpr 0 e) ty e1
> return (ty,UnaryMinus op e1')
> where opType op
> | op == minusId = freshConstrained [intType,floatType]
> | op == fminusId = return floatType
> | otherwise = internalError ("tcExpr unary " ++ name op)
> tcExpr m tcEnv tyEnv p e@(Apply e1 e2) =
> do
> ((alpha,beta),e1') <-
> tcExpr m tcEnv tyEnv p e1 >>=-
> tcArrow p "application" (ppExpr 0 e $-$ text "Term:" <+> ppExpr 0 e1)
> tcEnv
> e2' <- tcArg m tcEnv tyEnv p "application" (ppExpr 0 e) alpha e2
> return (beta,Apply e1' e2')
> tcExpr m tcEnv tyEnv p e@(InfixApply e1 op e2) =
> do
> ((alpha,beta,gamma),op') <-
> tcInfixOp tyEnv op >>=-
> tcBinary p "infix application"
> (ppExpr 0 e $-$ text "Operator:" <+> ppOp op) tcEnv
> e1' <- tcArg m tcEnv tyEnv p "infix application" (ppExpr 0 e) alpha e1
> e2' <- tcArg m tcEnv tyEnv p "infix application" (ppExpr 0 e) beta e2
> return (gamma,InfixApply e1' op' e2')
> tcExpr m tcEnv tyEnv p e@(LeftSection e1 op) =
> do