#include "HsVersions.h"
import HsSyn ( HsExpr(..), HsLit(..), ArithSeqInfo(..),
- HsMatchContext(..), mkMonoBind
+ HsMatchContext(..), HsDoContext(..), mkMonoBind
)
import RnHsSyn ( RenamedHsExpr, RenamedRecordBinds )
import TcHsSyn ( TcExpr, TcRecordBinds, mkHsLet )
import TcBinds ( tcBindsAndThen )
import TcEnv ( tcLookupClass, tcLookupGlobalId, tcLookupGlobal_maybe,
tcLookupTyCon, tcLookupDataCon, tcLookupId,
- tcExtendGlobalTyVars, tcLookupSyntaxName
+ tcExtendGlobalTyVars
)
import TcMatches ( tcMatchesCase, tcMatchLambda, tcStmts )
import TcMonoType ( tcHsSigType, checkSigTyVars, sigCtxt )
import TcPat ( badFieldCon, simpleHsLitTy )
import TcSimplify ( tcSimplifyCheck, tcSimplifyIPs )
-import TcType ( TcType, TcTauType,
- tcInstTyVars, tcInstType,
- newTyVarTy, newTyVarTys, zonkTcType )
-
-import FieldLabel ( fieldLabelName, fieldLabelType, fieldLabelTyCon )
-import Id ( idType, recordSelectorFieldLabel, isRecordSelector )
-import DataCon ( dataConFieldLabels, dataConSig,
- dataConStrictMarks, StrictnessMark(..)
+import TcMType ( tcInstTyVars, tcInstType,
+ newTyVarTy, newTyVarTys, zonkTcType,
+ unifyTauTy, unifyFunTy, unifyListTy, unifyTupleTy
)
-import Name ( Name )
-import Type ( mkFunTy, mkAppTy, mkTyConTy,
- splitFunTy_maybe, splitFunTys,
- mkTyConApp, splitSigmaTy, mkClassPred,
+import TcType ( tcSplitFunTys, tcSplitTyConApp,
+ isQualifiedTy,
+ mkFunTy, mkAppTy, mkTyConTy,
+ mkTyConApp, mkClassPred, tcFunArgTy,
isTauTy, tyVarsOfType, tyVarsOfTypes,
- isSigmaTy, splitAlgTyConApp, splitAlgTyConApp_maybe,
liftedTypeKind, openTypeKind, mkArrowKind,
+ tcSplitSigmaTy, tcTyConAppTyCon,
tidyOpenType
)
-import TyCon ( TyCon, tyConTyVars )
+import FieldLabel ( FieldLabel, fieldLabelName, fieldLabelType, fieldLabelTyCon )
+import Id ( idType, recordSelectorFieldLabel, isRecordSelector )
+import DataCon ( dataConFieldLabels, dataConSig,
+ dataConStrictMarks
+ )
+import Demand ( isMarkedStrict )
+import Name ( Name )
+import TyCon ( TyCon, tyConTyVars, isAlgTyCon, tyConDataCons )
import Subst ( mkTopTyVarSubst, substTheta, substTy )
import VarSet ( elemVarSet )
import TysWiredIn ( boolTy, mkListTy, listTyCon )
-import TcUnify ( unifyTauTy, unifyFunTy, unifyListTy, unifyTupleTy )
import PrelNames ( cCallableClassName,
cReturnableClassName,
enumFromName, enumFromThenName, negateName,
thenMName, failMName, returnMName, ioTyConName
)
import Outputable
-import Maybes ( maybeToBool, mapMaybe )
import ListSetOps ( minusList )
import Util
import CmdLineOpts
-> TcType -- Expected type (could be a polytpye)
-> TcM (TcExpr, LIE)
-tcExpr expr ty | isSigmaTy ty = -- Polymorphic case
- tcPolyExpr expr ty `thenTc` \ (expr', lie, _, _, _) ->
- returnTc (expr', lie)
+tcExpr expr ty | isQualifiedTy ty = -- Polymorphic case
+ tcPolyExpr expr ty `thenTc` \ (expr', lie, _, _, _) ->
+ returnTc (expr', lie)
- | otherwise = -- Monomorphic case
- tcMonoExpr expr ty
+ | otherwise = -- Monomorphic case
+ tcMonoExpr expr ty
\end{code}
tcMonoExpr (HsOverLit lit) res_ty = newOverloadedLit (LiteralOrigin lit) lit res_ty
tcMonoExpr (HsPar expr) res_ty = tcMonoExpr expr res_ty
-tcMonoExpr (NegApp expr) res_ty
- = tcLookupSyntaxName negateName `thenNF_Tc` \ neg ->
- tcMonoExpr (HsApp (HsVar neg) expr) res_ty
+tcMonoExpr (NegApp expr neg_name) res_ty
+ = tcMonoExpr (HsApp (HsVar neg_name) expr) res_ty
tcMonoExpr (HsLam match) res_ty
= tcMatchLambda match res_ty `thenTc` \ (match',lie) ->
\end{code}
\begin{code}
-tcMonoExpr in_expr@(ExplicitList exprs) res_ty -- Non-empty list
+tcMonoExpr in_expr@(ExplicitList _ exprs) res_ty -- Non-empty list
= unifyListTy res_ty `thenTc` \ elt_ty ->
mapAndUnzipTc (tc_elt elt_ty) exprs `thenTc` \ (exprs', lies) ->
- returnTc (ExplicitListOut elt_ty exprs', plusLIEs lies)
+ returnTc (ExplicitList elt_ty exprs', plusLIEs lies)
where
tc_elt elt_ty expr
= tcAddErrCtxt (listCtxt expr) $
= tcAddErrCtxt (recordConCtxt expr) $
tcId con_name `thenNF_Tc` \ (con_expr, con_lie, con_tau) ->
let
- (_, record_ty) = splitFunTys con_tau
- (tycon, ty_args, _) = splitAlgTyConApp record_ty
+ (_, record_ty) = tcSplitFunTys con_tau
+ (tycon, ty_args) = tcSplitTyConApp record_ty
in
- ASSERT( maybeToBool (splitAlgTyConApp_maybe record_ty ) )
+ ASSERT( isAlgTyCon tycon )
unifyTauTy res_ty record_ty `thenTc_`
-- Check that the record bindings match the constructor
tcRecordBinds tycon ty_args rbinds `thenTc` \ (rbinds', rbinds_lie) ->
let
- missing_s_fields = missingStrictFields rbinds data_con
+ (missing_s_fields, missing_fields) = missingFields rbinds data_con
in
checkTcM (null missing_s_fields)
(mapNF_Tc (addErrTc . missingStrictFieldCon con_name) missing_s_fields `thenNF_Tc_`
returnNF_Tc ()) `thenNF_Tc_`
- let
- missing_fields = missingFields rbinds data_con
- in
doptsTc Opt_WarnMissingFields `thenNF_Tc` \ warn ->
checkTcM (not (warn && not (null missing_fields)))
(mapNF_Tc ((warnTc True) . missingFieldCon con_name) missing_fields `thenNF_Tc_`
-- STEP 1
-- Figure out the tycon and data cons from the first field name
let
- (Just (AnId sel_id) : _) = maybe_sel_ids
- (_, _, tau) = splitSigmaTy (idType sel_id) -- Selectors can be overloaded
+ -- It's OK to use the non-tc splitters here (for a selector)
+ (Just (AnId sel_id) : _) = maybe_sel_ids
+ (_, _, tau) = tcSplitSigmaTy (idType sel_id) -- Selectors can be overloaded
-- when the data type has a context
- Just (data_ty, _) = splitFunTy_maybe tau -- Must succeed since sel_id is a selector
- (tycon, _, data_cons) = splitAlgTyConApp data_ty
+ data_ty = tcFunArgTy tau -- Must succeed since sel_id is a selector
+ tycon = tcTyConAppTyCon data_ty
+ data_cons = tyConDataCons tycon
(con_tyvars, _, _, _, _, _) = dataConSig (head data_cons)
in
tcInstTyVars con_tyvars `thenNF_Tc` \ (_, result_inst_tys, _) ->
newDicts RecordUpdOrigin theta' `thenNF_Tc` \ dicts ->
-- Phew!
- returnTc (RecordUpdOut record_expr' result_record_ty (map instToId dicts) rbinds',
+ returnTc (RecordUpdOut record_expr' record_ty result_record_ty (map instToId dicts) rbinds',
mkLIE dicts `plusLIE` record_lie `plusLIE` rbinds_lie)
tcMonoExpr (ArithSeqIn seq@(From expr)) res_ty
\begin{code}
tcMonoExpr in_expr@(ExprWithTySig expr poly_ty) res_ty
- = tcSetErrCtxt (exprSigCtxt in_expr) $
+ = tcAddErrCtxt (exprSigCtxt in_expr) $
tcHsSigType poly_ty `thenTc` \ sig_tc_ty ->
- if not (isSigmaTy sig_tc_ty) then
+ if not (isQualifiedTy sig_tc_ty) then
-- Easy case
unifyTauTy sig_tc_ty res_ty `thenTc_`
tcMonoExpr expr sig_tc_ty
tcMonoExpr (HsWith expr binds) res_ty
= tcMonoExpr expr res_ty `thenTc` \ (expr', expr_lie) ->
mapAndUnzipTc tcIPBind binds `thenTc` \ (pairs, bind_lies) ->
- tcSimplifyIPs (map fst binds) expr_lie `thenTc` \ (expr_lie', dict_binds) ->
+
+ -- If the binding binds ?x = E, we must now
+ -- discharge any ?x constraints in expr_lie
+ tcSimplifyIPs (map fst pairs) expr_lie `thenTc` \ (expr_lie', dict_binds) ->
let
binds' = [(instToId ip, rhs) | (ip,rhs) <- pairs]
expr'' = HsLet (mkMonoBind dict_binds [] Recursive) expr'
let
(env1, exp_ty'') = tidyOpenType tidy_env exp_ty'
(env2, act_ty'') = tidyOpenType env1 act_ty'
- (exp_args, _) = splitFunTys exp_ty''
- (act_args, _) = splitFunTys act_ty''
+ (exp_args, _) = tcSplitFunTys exp_ty''
+ (act_args, _) = tcSplitFunTys act_ty''
message | length exp_args < length act_args = wrongArgsCtxt "too few" fun args
| length exp_args > length act_args = wrongArgsCtxt "too many" fun args
_ -> newTyVarTy (mkArrowKind liftedTypeKind liftedTypeKind) `thenNF_Tc` \ m_ty ->
newTyVarTy liftedTypeKind `thenNF_Tc` \ elt_ty ->
- unifyTauTy res_ty (mkAppTy m_ty elt_ty) `thenTc_`
+ unifyTauTy res_ty (mkAppTy m_ty elt_ty) `thenTc_`
returnNF_Tc (m_ty, (mkAppTy m_ty, elt_ty))
) `thenNF_Tc` \ (tc_ty, m_ty) ->
- tcStmts do_or_lc m_ty stmts `thenTc` \ (stmts', stmts_lie) ->
+ tcStmts (DoCtxt do_or_lc) m_ty stmts `thenTc` \ (stmts', stmts_lie) ->
-- Build the then and zero methods in case we need them
-- It's important that "then" and "return" appear just once in the final LIE,
where
field_names = map fieldLabelName (dataConFieldLabels data_con)
-missingStrictFields rbinds data_con
- = [ fn | fn <- strict_field_names,
- not (fn `elem` field_names_used)
- ]
- where
- field_names_used = [ field_name | (field_name, _, _) <- rbinds ]
- strict_field_names = mapMaybe isStrict field_info
-
- isStrict (fl, MarkedStrict) = Just (fieldLabelName fl)
- isStrict _ = Nothing
-
- field_info = zip (dataConFieldLabels data_con)
- (dataConStrictMarks data_con)
-
missingFields rbinds data_con
- = [ fn | fn <- non_strict_field_names, not (fn `elem` field_names_used) ]
+ | null field_labels = ([], []) -- Not declared as a record;
+ -- But C{} is still valid
+ | otherwise
+ = (missing_strict_fields, other_missing_fields)
where
- field_names_used = [ field_name | (field_name, _, _) <- rbinds ]
-
- -- missing strict fields have already been flagged as
- -- being so, so leave them out here.
- non_strict_field_names = mapMaybe isn'tStrict field_info
-
- isn'tStrict (fl, MarkedStrict) = Nothing
- isn'tStrict (fl, _) = Just (fieldLabelName fl)
-
- field_info = zip (dataConFieldLabels data_con)
- (dataConStrictMarks data_con)
+ missing_strict_fields
+ = [ fl | (fl, str) <- field_info,
+ isMarkedStrict str,
+ not (fieldLabelName fl `elem` field_names_used)
+ ]
+ other_missing_fields
+ = [ fl | (fl, str) <- field_info,
+ not (isMarkedStrict str),
+ not (fieldLabelName fl `elem` field_names_used)
+ ]
+ field_names_used = [ field_name | (field_name, _, _) <- rbinds ]
+ field_labels = dataConFieldLabels data_con
+
+ field_info = zipEqual "missingFields"
+ field_labels
+ (drop (length ex_theta) (dataConStrictMarks data_con))
+ -- The 'drop' is because dataConStrictMarks
+ -- includes the existential dictionaries
+ (_, _, _, ex_theta, _, _) = dataConSig data_con
\end{code}
%************************************************************************
Mini-utils:
-\begin{code}
-pp_nest_hang :: String -> SDoc -> SDoc
-pp_nest_hang lbl stuff = nest 2 (hang (text lbl) 4 stuff)
-\end{code}
-
Boring and alphabetical:
\begin{code}
arithSeqCtxt expr
notSelector field
= hsep [quotes (ppr field), ptext SLIT("is not a record selector")]
-missingStrictFieldCon :: Name -> Name -> SDoc
+missingStrictFieldCon :: Name -> FieldLabel -> SDoc
missingStrictFieldCon con field
= hsep [ptext SLIT("Constructor") <+> quotes (ppr con),
ptext SLIT("does not have the required strict field"), quotes (ppr field)]
-missingFieldCon :: Name -> Name -> SDoc
+missingFieldCon :: Name -> FieldLabel -> SDoc
missingFieldCon con field
= hsep [ptext SLIT("Field") <+> quotes (ppr field),
ptext SLIT("is not initialised")]