%
+% (c) The University of Glasgow 2006
% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
%
\section[TcExpr]{Typecheck an expression}
#ifdef GHCI /* Only if bootstrapped */
import {-# SOURCE #-} TcSplice( tcSpliceExpr, tcBracket )
-import HsSyn ( nlHsVar )
-import Id ( Id )
-import Name ( isExternalName )
-import TcType ( isTauTy )
-import TcEnv ( checkWellStaged )
-import HsSyn ( nlHsApp )
import qualified DsMeta
#endif
-import HsSyn ( HsExpr(..), LHsExpr, ArithSeqInfo(..), recBindFields,
- HsMatchContext(..), HsRecordBinds,
- mkHsCoerce, mkHsApp, mkHsDictApp, mkHsTyApp )
-import TcHsSyn ( hsLitType )
+import HsSyn
+import TcHsSyn
import TcRnMonad
-import TcUnify ( tcInfer, tcSubExp, tcFunResTy, tcGen, boxyUnify, subFunTys, zapToMonotype, stripBoxyType,
- boxySplitListTy, boxySplitTyConApp, wrapFunResCoercion, boxySubMatchType,
- unBox )
-import BasicTypes ( Arity, isMarkedStrict )
-import Inst ( newMethodFromName, newIPDict, instToId,
- newDicts, newMethodWithGivenTy, tcInstStupidTheta )
-import TcBinds ( tcLocalBinds )
-import TcEnv ( tcLookup, tcLookupId,
- tcLookupDataCon, tcLookupGlobalId
- )
-import TcArrows ( tcProc )
-import TcMatches ( tcMatchesCase, tcMatchLambda, tcDoStmts, TcMatchCtxt(..) )
-import TcHsType ( tcHsSigType, UserTypeCtxt(..) )
-import TcPat ( tcOverloadedLit, badFieldCon )
-import TcMType ( tcInstTyVars, newFlexiTyVarTy, newBoxyTyVars, readFilledBox,
- tcInstBoxyTyVar, tcInstTyVar )
-import TcType ( TcType, TcSigmaType, TcRhoType,
- BoxySigmaType, BoxyRhoType, ThetaType,
- mkTyVarTys, mkFunTys, tcMultiSplitSigmaTy, tcSplitFunTysN,
- isSigmaTy, mkFunTy, mkTyConApp, isLinearPred,
- exactTyVarsOfType, exactTyVarsOfTypes, mkTyVarTy,
- zipTopTvSubst, zipOpenTvSubst, substTys, substTyVar, lookupTyVar
- )
-import Kind ( argTypeKind )
-
-import Id ( idType, idName, recordSelectorFieldLabel, isRecordSelector,
- isNaughtyRecordSelector, isDataConId_maybe )
-import DataCon ( DataCon, dataConFieldLabels, dataConStrictMarks, dataConSourceArity,
- dataConWrapId, isVanillaDataCon, dataConTyVars, dataConOrigArgTys )
-import Name ( Name )
-import TyCon ( FieldLabel, tyConStupidTheta, tyConDataCons )
-import Type ( substTheta, substTy )
-import Var ( TyVar, tyVarKind )
-import VarSet ( emptyVarSet, elemVarSet, unionVarSet )
-import TysWiredIn ( boolTy, parrTyCon, tupleTyCon )
-import PrelNames ( enumFromName, enumFromThenName,
- enumFromToName, enumFromThenToName,
- enumFromToPName, enumFromThenToPName, negateName
- )
+import TcUnify
+import BasicTypes
+import Inst
+import TcBinds
+import TcEnv
+import TcArrows
+import TcMatches
+import TcHsType
+import TcPat
+import TcMType
+import TcType
+import Id
+import DataCon
+import Name
+import TyCon
+import Type
+import Var
+import VarSet
+import TysWiredIn
+import PrelNames
+import PrimOp
import DynFlags
-import StaticFlags ( opt_NoMethodSharing )
-import HscTypes ( TyThing(..) )
-import SrcLoc ( Located(..), unLoc, noLoc, getLoc )
+import StaticFlags
+import HscTypes
+import SrcLoc
import Util
-import ListSetOps ( assocMaybe )
-import Maybes ( catMaybes )
+import ListSetOps
+import Maybes
import Outputable
import FastString
-
-#ifdef DEBUG
-import TyCon ( tyConArity )
-#endif
\end{code}
%************************************************************************
tcPolyExprNC expr res_ty
| isSigmaTy res_ty
- = do { (gen_fn, expr') <- tcGen res_ty emptyVarSet (tcPolyExprNC expr)
+ = do { (gen_fn, expr') <- tcGen res_ty emptyVarSet (\_ -> tcPolyExprNC expr)
-- Note the recursive call to tcPolyExpr, because the
-- type may have multiple layers of for-alls
- ; return (L (getLoc expr') (mkHsCoerce gen_fn (unLoc expr'))) }
+ ; return (mkLHsWrap gen_fn expr') }
| otherwise
= tcMonoExpr expr res_ty
; co_fn <- tcSubExp ip_ty res_ty
; (ip', inst) <- newIPDict (IPOccOrigin ip) ip ip_ty
; extendLIE inst
- ; return (mkHsCoerce co_fn (HsIPVar ip')) }
+ ; return (mkHsWrap co_fn (HsIPVar ip')) }
tcExpr (HsApp e1 e2) res_ty
= go e1 [e2]
go :: LHsExpr Name -> [LHsExpr Name] -> TcM (HsExpr TcId)
go (L _ (HsApp e1 e2)) args = go e1 (e2:args)
go lfun@(L loc fun) args
- = do { (fun', args') <- addErrCtxt (callCtxt lfun args) $
+ = do { (fun', args') <- -- addErrCtxt (callCtxt lfun args) $
tcApp fun (length args) (tcArgs lfun args) res_ty
; return (unLoc (foldl mkHsApp (L loc fun') args')) }
tcExpr (HsLam match) res_ty
= do { (co_fn, match') <- tcMatchLambda match res_ty
- ; return (mkHsCoerce co_fn (HsLam match')) }
+ ; return (mkHsWrap co_fn (HsLam match')) }
tcExpr in_expr@(ExprWithTySig expr sig_ty) res_ty
= do { sig_tc_ty <- tcHsSigType ExprSigCtxt sig_ty
- ; expr' <- tcPolyExpr expr sig_tc_ty
+
+ -- Remember to extend the lexical type-variable environment
+ ; (gen_fn, expr') <- tcGen sig_tc_ty emptyVarSet (\ skol_tvs res_ty ->
+ tcExtendTyVarEnv2 (hsExplicitTvs sig_ty `zip` mkTyVarTys skol_tvs) $
+ tcPolyExprNC expr res_ty)
+
; co_fn <- tcSubExp sig_tc_ty res_ty
- ; return (mkHsCoerce co_fn (ExprWithTySigOut expr' sig_ty)) }
+ ; return (mkHsWrap co_fn (ExprWithTySigOut (mkLHsWrap gen_fn expr') sig_ty)) }
tcExpr (HsType ty) res_ty
= failWithTc (text "Can't handle type argument:" <+> ppr ty)
tcExpr in_expr@(SectionR lop@(L loc op) arg2) res_ty
= do { (co_fn, (op', arg2')) <- subFunTys doc 1 res_ty $ \ [arg1_ty'] res_ty' ->
tcApp op 2 (tc_args arg1_ty') res_ty'
- ; return (mkHsCoerce co_fn (SectionR (L loc op') arg2')) }
+ ; return (mkHsWrap co_fn (SectionR (L loc op') arg2')) }
where
doc = ptext SLIT("The section") <+> quotes (ppr in_expr)
<+> ptext SLIT("takes one argument")
tc_args arg1_ty' [arg1_ty, arg2_ty]
= do { boxyUnify arg1_ty' arg1_ty
; tcArg lop (arg2, arg2_ty, 2) }
+ tc_args arg1_ty' other = panic "tcExpr SectionR"
\end{code}
\begin{code}
; return (HsCase scrut' matches') }
where
match_ctxt = MC { mc_what = CaseAlt,
- mc_body = tcPolyExpr }
+ mc_body = tcBody }
tcExpr (HsIf pred b1 b2) res_ty
= do { pred' <- addErrCtxt (predCtxt pred) $
let
field_names = map fst rbinds
in
- mappM (tcLookupGlobalId.unLoc) field_names `thenM` \ sel_ids ->
+ mappM (tcLookupField . unLoc) field_names `thenM` \ sel_ids ->
-- The renamer has already checked that they
-- are all in scope
let
-- A constructor is only relevant to this process if
-- it contains *all* the fields that are being updated
con1 = head relevant_cons -- A representative constructor
- con1_tyvars = dataConTyVars con1
+ con1_tyvars = dataConUnivTyVars con1
con1_flds = dataConFieldLabels con1
con1_arg_tys = dataConOrigArgTys con1
common_tyvars = exactTyVarsOfTypes [ty | (fld,ty) <- con1_flds `zip` con1_arg_tys
-- dictionaries for the data type context, since we are going to
-- do pattern matching over the data cons.
--
- -- What dictionaries do we need?
- -- We just take the context of the first data constructor
- -- This isn't right, but I just can't bear to union up all the relevant ones
+ -- What dictionaries do we need? The tyConStupidTheta tells us.
let
theta' = substTheta inst_env (tyConStupidTheta tycon)
in
- newDicts RecordUpdOrigin theta' `thenM` \ dicts ->
- extendLIEs dicts `thenM_`
+ instStupidTheta RecordUpdOrigin theta' `thenM_`
-- Phew!
- returnM (mkHsCoerce co_fn (RecordUpd record_expr' rbinds' record_ty result_record_ty))
+ returnM (mkHsWrap co_fn (RecordUpd record_expr' rbinds' record_ty result_record_ty))
\end{code}
-- Then fres <= bx_(k+1) -> ... -> bx_n -> res_ty
tcIdApp fun_name n_args arg_checker res_ty
- = do { fun_id <- lookupFun (OccurrenceOf fun_name) fun_name
+ = do { let orig = OccurrenceOf fun_name
+ ; (fun, fun_ty) <- lookupFun orig fun_name
-- Split up the function type
- ; let (tv_theta_prs, rho) = tcMultiSplitSigmaTy (idType fun_id)
+ ; let (tv_theta_prs, rho) = tcMultiSplitSigmaTy fun_ty
(fun_arg_tys, fun_res_ty) = tcSplitFunTysN rho n_args
qtvs = concatMap fst tv_theta_prs -- Quantified tyvars
; extra_arg_boxes <- newBoxyTyVars (replicate n_missing_args argTypeKind)
; let extra_arg_tys' = mkTyVarTys extra_arg_boxes
res_ty' = mkFunTys extra_arg_tys' res_ty
- subst = boxySubMatchType arg_qtvs fun_res_ty res_ty'
- -- Only bind arg_qtvs, since only they will be
- -- *definitely* be filled in by arg_checker
- -- E.g. error :: forall a. String -> a
- -- (error "foo") :: bx5
- -- Don't make subst [a |-> bx5]
- -- because then the result subsumption becomes
- -- bx5 ~ bx5
- -- and the unifer doesn't expect the
- -- same box on both sides
- inst_qtv tv | Just boxy_ty <- lookupTyVar subst tv = return boxy_ty
- | tv `elemVarSet` tau_qtvs = do { tv' <- tcInstBoxyTyVar tv
- ; return (mkTyVarTy tv') }
- | otherwise = do { tv' <- tcInstTyVar tv
- ; return (mkTyVarTy tv') }
- -- The 'otherwise' case handles type variables that are
- -- mentioned only in the constraints, not in argument or
- -- result types. We'll make them tau-types
-
- ; qtys' <- mapM inst_qtv qtvs
+ ; qtys' <- preSubType qtvs tau_qtvs fun_res_ty res_ty'
; let arg_subst = zipOpenTvSubst qtvs qtys'
fun_arg_tys' = substTys arg_subst fun_arg_tys
-- Doing so will fill arg_qtvs and extra_arg_tys'
; args' <- arg_checker (fun_arg_tys' ++ extra_arg_tys')
+ -- Strip boxes from the qtvs that have been filled in by the arg checking
+ -- AND any variables that are mentioned in neither arg nor result
+ -- the latter are mentioned only in constraints; stripBoxyType will
+ -- fill them with a monotype
; let strip qtv qty' | qtv `elemVarSet` arg_qtvs = stripBoxyType qty'
- | otherwise = return qty'
+ | otherwise = return qty'
; qtys'' <- zipWithM strip qtvs qtys'
; extra_arg_tys'' <- mapM readFilledBox extra_arg_boxes
-- And pack up the results
-- By applying the coercion just to the *function* we can make
-- tcFun work nicely for OpApp and Sections too
- ; fun' <- instFun fun_id qtvs qtys'' tv_theta_prs
+ ; fun' <- instFun orig fun res_subst tv_theta_prs
; co_fn' <- wrapFunResCoercion fun_arg_tys' co_fn
- ; return (mkHsCoerce co_fn' fun', args') }
+ ; return (mkHsWrap co_fn' fun', args') }
\end{code}
Note [Silly type synonyms in smart-app]
-> TcM (HsExpr TcId)
tcId orig fun_name res_ty
= do { traceTc (text "tcId" <+> ppr fun_name <+> ppr res_ty)
- ; fun_id <- lookupFun orig fun_name
+ ; (fun, fun_ty) <- lookupFun orig fun_name
-- Split up the function type
- ; let (tv_theta_prs, fun_tau) = tcMultiSplitSigmaTy (idType fun_id)
- qtvs = concatMap fst tv_theta_prs -- Quantified tyvars
- tau_qtvs = exactTyVarsOfType fun_tau -- Mentiond in the tau part
- inst_qtv tv | tv `elemVarSet` tau_qtvs = do { tv' <- tcInstBoxyTyVar tv
- ; return (mkTyVarTy tv') }
- | otherwise = do { tv' <- tcInstTyVar tv
- ; return (mkTyVarTy tv') }
+ ; let (tv_theta_prs, fun_tau) = tcMultiSplitSigmaTy fun_ty
+ qtvs = concatMap fst tv_theta_prs -- Quantified tyvars
+ tau_qtvs = exactTyVarsOfType fun_tau -- Mentioned in the tau part
+ ; qtv_tys <- preSubType qtvs tau_qtvs fun_tau res_ty
-- Do the subsumption check wrt the result type
- ; qtv_tys <- mapM inst_qtv qtvs
- ; let res_subst = zipTopTvSubst qtvs qtv_tys
- fun_tau' = substTy res_subst fun_tau
+ ; let res_subst = zipTopTvSubst qtvs qtv_tys
+ fun_tau' = substTy res_subst fun_tau
; co_fn <- tcFunResTy fun_name fun_tau' res_ty
-- And pack up the results
- ; fun' <- instFun fun_id qtvs qtv_tys tv_theta_prs
- ; return (mkHsCoerce co_fn fun') }
+ ; fun' <- instFun orig fun res_subst tv_theta_prs
+ ; return (mkHsWrap co_fn fun') }
-- Note [Push result type in]
--
tcSyntaxOp orig other ty = pprPanic "tcSyntaxOp" (ppr other)
---------------------------
-instFun :: TcId
- -> [TyVar] -> [TcType] -- Quantified type variables and
- -- their instantiating types
- -> [([TyVar], ThetaType)] -- Stuff to instantiate
+instFun :: InstOrigin
+ -> HsExpr TcId
+ -> TvSubst -- The instantiating substitution
+ -> [([TyVar], ThetaType)] -- Stuff to instantiate
-> TcM (HsExpr TcId)
-instFun fun_id qtvs qtv_tys []
- = return (HsVar fun_id) -- Common short cut
-instFun fun_id qtvs qtv_tys tv_theta_prs
- = do { let subst = zipOpenTvSubst qtvs qtv_tys
- ty_theta_prs' = map subst_pr tv_theta_prs
- subst_pr (tvs, theta) = (map (substTyVar subst) tvs,
- substTheta subst theta)
+instFun orig fun subst []
+ = return fun -- Common short cut
- -- The ty_theta_prs' is always non-empty
- ((tys1',theta1') : further_prs') = ty_theta_prs'
-
- -- First, chuck in the constraints from
- -- the "stupid theta" of a data constructor (sigh)
- ; case isDataConId_maybe fun_id of
- Just con -> tcInstStupidTheta con tys1'
- Nothing -> return ()
-
- ; if want_method_inst theta1'
- then do { meth_id <- newMethodWithGivenTy orig fun_id tys1'
- -- See Note [Multiple instantiation]
- ; go (HsVar meth_id) further_prs' }
- else go (HsVar fun_id) ty_theta_prs'
- }
+instFun orig fun subst tv_theta_prs
+ = do { let ty_theta_prs' = map subst_pr tv_theta_prs
+
+ -- Make two ad-hoc checks
+ ; doStupidChecks fun ty_theta_prs'
+
+ -- Now do normal instantiation
+ ; go True fun ty_theta_prs' }
where
- orig = OccurrenceOf (idName fun_id)
+ subst_pr (tvs, theta)
+ = (map (substTyVar subst) tvs, substTheta subst theta)
+
+ go _ fun [] = return fun
- go fun [] = return fun
+ go True (HsVar fun_id) ((tys,theta) : prs)
+ | want_method_inst theta
+ = do { meth_id <- newMethodWithGivenTy orig fun_id tys
+ ; go False (HsVar meth_id) prs }
+ -- Go round with 'False' to prevent further use
+ -- of newMethod: see Note [Multiple instantiation]
- go fun ((tys, theta) : prs)
- = do { dicts <- newDicts orig theta
- ; extendLIEs dicts
- ; let the_app = unLoc $ mkHsDictApp (mkHsTyApp (noLoc fun) tys)
- (map instToId dicts)
- ; go the_app prs }
+ go _ fun ((tys, theta) : prs)
+ = do { co_fn <- instCall orig tys theta
+ ; go False (HsWrap co_fn fun) prs }
- -- Hack Alert (want_method_inst)!
-- See Note [No method sharing]
- -- If f :: (%x :: T) => Int -> Int
- -- Then if we have two separate calls, (f 3, f 4), we cannot
- -- make a method constraint that then gets shared, thus:
- -- let m = f %x in (m 3, m 4)
- -- because that loses the linearity of the constraint.
- -- The simplest thing to do is never to construct a method constraint
- -- in the first place that has a linear implicit parameter in it.
- want_method_inst theta = not (null theta) -- Overloaded
- && not (any isLinearPred theta) -- Not linear
+ want_method_inst theta = not (null theta) -- Overloaded
&& not opt_NoMethodSharing
- -- See Note [No method sharing] below
\end{code}
Note [Multiple instantiation]
\end{code}
+Note [tagToEnum#]
+~~~~~~~~~~~~~~~~~
+Nasty check to ensure that tagToEnum# is applied to a type that is an
+enumeration TyCon. Unification may refine the type later, but this
+check won't see that, alas. It's crude but it works.
+
+Here's are two cases that should fail
+ f :: forall a. a
+ f = tagToEnum# 0 -- Can't do tagToEnum# at a type variable
+
+ g :: Int
+ g = tagToEnum# 0 -- Int is not an enumeration
+
+
+\begin{code}
+doStupidChecks :: HsExpr TcId
+ -> [([TcType], ThetaType)]
+ -> TcM ()
+-- Check two tiresome and ad-hoc cases
+-- (a) the "stupid theta" for a data con; add the constraints
+-- from the "stupid theta" of a data constructor (sigh)
+-- (b) deal with the tagToEnum# problem: see Note [tagToEnum#]
+
+doStupidChecks (HsVar fun_id) ((tys,_):_)
+ | Just con <- isDataConId_maybe fun_id -- (a)
+ = addDataConStupidTheta con tys
+
+ | fun_id `hasKey` tagToEnumKey -- (b)
+ = do { tys' <- zonkTcTypes tys
+ ; checkTc (ok tys') (tagToEnumError tys')
+ }
+ where
+ ok [] = False
+ ok (ty:tys) = case tcSplitTyConApp_maybe ty of
+ Just (tc,_) -> isEnumerationTyCon tc
+ Nothing -> False
+
+doStupidChecks fun tv_theta_prs
+ = return () -- The common case
+
+
+tagToEnumError tys
+ = hang (ptext SLIT("Bad call to tagToEnum#") <+> at_type)
+ 2 (vcat [ptext SLIT("Specify the type by giving a type signature"),
+ ptext SLIT("e.g. (tagToEnum# x) :: Bool")])
+ where
+ at_type | null tys = empty -- Probably never happens
+ | otherwise = ptext SLIT("at type") <+> ppr (head tys)
+\end{code}
+
%************************************************************************
%* *
\subsection{@tcId@ typchecks an identifier occurrence}
%************************************************************************
\begin{code}
-lookupFun :: InstOrigin -> Name -> TcM TcId
+lookupFun :: InstOrigin -> Name -> TcM (HsExpr TcId, TcType)
lookupFun orig id_name
= do { thing <- tcLookup id_name
; case thing of
- AGlobal (ADataCon con) -> return (dataConWrapId con)
+ AGlobal (ADataCon con) -> return (HsVar wrap_id, idType wrap_id)
+ where
+ wrap_id = dataConWrapId con
AGlobal (AnId id)
| isNaughtyRecordSelector id -> failWithTc (naughtyRecordSel id)
- | otherwise -> return id
+ | otherwise -> return (HsVar id, idType id)
-- A global cannot possibly be ill-staged
-- nor does it need the 'lifting' treatment
-#ifndef GHCI
- ATcId id th_level _ -> return id -- Non-TH case
-#else
- ATcId id th_level _ -> do { use_stage <- getStage -- TH case
- ; thLocalId orig id_name id th_level use_stage }
-#endif
+ ATcId { tct_id = id, tct_type = ty, tct_co = mb_co, tct_level = lvl }
+ -> do { thLocalId orig id ty lvl
+ ; case mb_co of
+ Nothing -> return (HsVar id, ty) -- Wobbly, or no free vars
+ Just co -> return (mkHsWrap co (HsVar id), ty) }
other -> failWithTc (ppr other <+> ptext SLIT("used where a value identifer was expected"))
}
-#ifdef GHCI /* GHCI and TH is on */
+#ifndef GHCI /* GHCI and TH is off */
--------------------------------------
-- thLocalId : Check for cross-stage lifting
-thLocalId orig id_name id th_bind_lvl (Brack use_lvl ps_var lie_var)
- | use_lvl > th_bind_lvl
- = thBrackId orig id_name id ps_var lie_var
-thLocalId orig id_name id th_bind_lvl use_stage
- = do { checkWellStaged (quotes (ppr id)) th_bind_lvl use_stage
- ; return id }
+thLocalId orig id id_ty th_bind_lvl
+ = return ()
+
+#else /* GHCI and TH is on */
+thLocalId orig id id_ty th_bind_lvl
+ = do { use_stage <- getStage -- TH case
+ ; case use_stage of
+ Brack use_lvl ps_var lie_var | use_lvl > th_bind_lvl
+ -> thBrackId orig id ps_var lie_var
+ other -> do { checkWellStaged (quotes (ppr id)) th_bind_lvl use_stage
+ ; return id }
+ }
--------------------------------------
-thBrackId orig id_name id ps_var lie_var
+thBrackId orig id ps_var lie_var
| isExternalName id_name
= -- Top-level identifiers in this module,
-- (which have External Names)
; writeMutVar ps_var ((id_name, nlHsApp (nlHsVar lift) (nlHsVar id)) : ps)
; return id } }
+ where
+ id_name = idName id
#endif /* GHCI */
\end{code}
| Just field_ty <- assocMaybe flds_w_tys field_lbl
= addErrCtxt (fieldCtxt field_lbl) $
do { rhs' <- tcPolyExprNC rhs field_ty
- ; sel_id <- tcLookupId field_lbl
+ ; sel_id <- tcLookupField field_lbl
; ASSERT( isRecordSelector sel_id )
return (Just (L loc sel_id, rhs')) }
| otherwise