summaryrefslogtreecommitdiff
path: root/compiler/typecheck/TcExpr.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/typecheck/TcExpr.lhs')
-rw-r--r--compiler/typecheck/TcExpr.lhs320
1 files changed, 253 insertions, 67 deletions
diff --git a/compiler/typecheck/TcExpr.lhs b/compiler/typecheck/TcExpr.lhs
index 29020b4cb9..7ac896e962 100644
--- a/compiler/typecheck/TcExpr.lhs
+++ b/compiler/typecheck/TcExpr.lhs
@@ -10,7 +10,8 @@ c%
module TcExpr ( tcPolyExpr, tcPolyExprNC, tcMonoExpr, tcMonoExprNC,
tcInferRho, tcInferRhoNC,
tcSyntaxOp, tcCheckId,
- addExprErrCtxt) where
+ addExprErrCtxt,
+ getFixedTyVars ) where
#include "HsVersions.h"
@@ -48,7 +49,8 @@ import Var
import VarSet
import VarEnv
import TysWiredIn
-import TysPrim( intPrimTy )
+import TysPrim
+import MkId
import PrimOp( tagToEnumKey )
import PrelNames
import DynFlags
@@ -634,12 +636,18 @@ In the outgoing (HsRecordUpd scrut binds cons in_inst_tys out_inst_tys):
family example], in_inst_tys = [t1,t2], out_inst_tys = [t3,t2]
\begin{code}
-tcExpr (RecordUpd record_expr rbinds _ _ _) res_ty
- = ASSERT( notNull upd_fld_names )
- do {
+tcExpr (RecordUpd record_expr rbnds _ _ _) res_ty
+ = ASSERT( notNull (hsRecFields rbnds) ) do {
+ -- STEP -1 See Note [Disambiguating record updates]
+ -- After this we know that rbinds is unambiguous
+ rbinds <- disambiguateRecordBinds record_expr rbnds res_ty
+ ; let upd_flds = hsRecFieldsUnambiguous rbinds
+ upd_fld_occs = map fst upd_flds
+ upd_fld_names = map snd upd_flds
+
-- STEP 0
-- Check that the field names are really field names
- ; sel_ids <- mapM tcLookupField upd_fld_names
+ ; sel_ids <- mapM tcLookupId upd_fld_names
-- The renamer has already checked that
-- selectors are all in scope
; let bad_guys = [ setSrcSpan loc $ addErrTc (notSelector fld_name)
@@ -652,12 +660,11 @@ tcExpr (RecordUpd record_expr rbinds _ _ _) res_ty
-- Figure out the tycon and data cons from the first field name
; let -- It's OK to use the non-tc splitters here (for a selector)
sel_id : _ = sel_ids
- (tycon, _) = recordSelectorFieldLabel sel_id -- We've failed already if
+ tycon = recordSelectorTyCon sel_id -- We've failed already if
data_cons = tyConDataCons tycon -- it's not a field label
-- NB: for a data type family, the tycon is the instance tycon
- relevant_cons = filter is_relevant data_cons
- is_relevant con = all (`elem` dataConFieldLabels con) upd_fld_names
+ relevant_cons = tyConDataConsWithFields tycon upd_fld_occs
-- A constructor is only relevant to this process if
-- it contains *all* the fields that are being updated
-- Other ones will cause a runtime error if they occur
@@ -665,7 +672,7 @@ tcExpr (RecordUpd record_expr rbinds _ _ _) res_ty
-- Take apart a representative constructor
con1 = ASSERT( not (null relevant_cons) ) head relevant_cons
(con1_tvs, _, _, _, con1_arg_tys, _) = dataConFullSig con1
- con1_flds = dataConFieldLabels con1
+ con1_flds = map flLabel $ dataConFieldLabels con1
con1_res_ty = mkFamilyTyConApp tycon (mkTyVarTys con1_tvs)
-- Step 2
@@ -676,13 +683,10 @@ tcExpr (RecordUpd record_expr rbinds _ _ _) res_ty
-- STEP 3 Note [Criteria for update]
-- Check that each updated field is polymorphic; that is, its type
-- mentions only the universally-quantified variables of the data con
- ; let flds1_w_tys = zipEqual "tcExpr:RecConUpd" con1_flds con1_arg_tys
- upd_flds1_w_tys = filter is_updated flds1_w_tys
- is_updated (fld,_) = fld `elem` upd_fld_names
-
- bad_upd_flds = filter bad_fld upd_flds1_w_tys
- con1_tv_set = mkVarSet con1_tvs
- bad_fld (fld, ty) = fld `elem` upd_fld_names &&
+ ; let flds1_w_tys = zipEqual "tcExpr:RecConUpd" con1_flds con1_arg_tys
+ bad_upd_flds = filter bad_fld flds1_w_tys
+ con1_tv_set = mkVarSet con1_tvs
+ bad_fld (fld, ty) = fld `elem` upd_fld_occs &&
not (tyVarsOfType ty `subVarSet` con1_tv_set)
; checkTc (null bad_upd_flds) (badFieldTypes bad_upd_flds)
@@ -693,7 +697,7 @@ tcExpr (RecordUpd record_expr rbinds _ _ _) res_ty
-- These are variables that appear in *any* arg of *any* of the
-- relevant constructors *except* in the updated fields
--
- ; let fixed_tvs = getFixedTyVars con1_tvs relevant_cons
+ ; let fixed_tvs = getFixedTyVars upd_fld_occs con1_tvs relevant_cons
is_fixed_tv tv = tv `elemVarSet` fixed_tvs
mk_inst_ty :: TvSubst -> (TKVar, TcType) -> TcM (TvSubst, TcType)
@@ -735,27 +739,47 @@ tcExpr (RecordUpd record_expr rbinds _ _ _) res_ty
; return $ mkHsWrapCo co_res $
RecordUpd (mkLHsWrap scrut_co record_expr') rbinds'
relevant_cons scrut_inst_tys result_inst_tys }
- where
- upd_fld_names = hsRecFields rbinds
+\end{code}
- getFixedTyVars :: [TyVar] -> [DataCon] -> TyVarSet
- -- These tyvars must not change across the updates
- getFixedTyVars tvs1 cons
- = mkVarSet [tv1 | con <- cons
- , let (tvs, theta, arg_tys, _) = dataConSig con
- flds = dataConFieldLabels con
- fixed_tvs = exactTyVarsOfTypes fixed_tys
- -- fixed_tys: See Note [Type of a record update]
- `unionVarSet` tyVarsOfTypes theta
- -- Universally-quantified tyvars that
- -- appear in any of the *implicit*
- -- arguments to the constructor are fixed
- -- See Note [Implicit type sharing]
- fixed_tys = [ty | (fld,ty) <- zip flds arg_tys
- , not (fld `elem` upd_fld_names)]
- , (tv1,tv) <- tvs1 `zip` tvs -- Discards existentials in tvs
- , tv `elemVarSet` fixed_tvs ]
+When typechecking a use of an overloaded record field, we need to
+construct an appropriate instantiation of
+
+ field :: forall p r n t . Accessor p r n t => Proxy# n -> p r t
+
+so we supply
+
+ p = metavariable
+ r = metavariable
+ t = metavariable
+ n = field label
+
+ Accessor p r n t = wanted constraint
+ Proxy# n = proxy#
+
+and end up with something of type p r t.
+
+\begin{code}
+tcExpr (HsOverloadedRecFld lbl) res_ty
+ = do { p <- newFlexiTyVarTy (mkArrowKind liftedTypeKind
+ (mkArrowKind liftedTypeKind liftedTypeKind))
+ ; r <- newFlexiTyVarTy liftedTypeKind
+ ; t <- newFlexiTyVarTy liftedTypeKind
+ ; accessorClass <- tcLookupClass accessorClassName
+ ; acs_var <- emitWanted origin (mkClassPred accessorClass [p, r, n, t])
+ ; field <- tcLookupId fieldName
+ ; loc <- getSrcSpanM
+ ; let wrap = mkWpEvVarApps [acs_var] <.> mkWpTyApps [p, r, n, t]
+ proxy_arg = noLoc (mkHsWrap (mkWpTyApps [typeSymbolKind, n])
+ (HsVar proxyHashId))
+ tm = L loc (mkHsWrap wrap (HsVar field)) `HsApp` proxy_arg
+ ; tcWrapResult tm (mkAppTys p [r, t]) res_ty }
+ where
+ n = mkStrLitTy lbl
+ origin = OccurrenceOfRecSel (mkVarUnqual lbl)
+
+tcExpr (HsSingleRecFld f sel_name) res_ty
+ = tcCheckRecSelId f sel_name res_ty
\end{code}
%************************************************************************
@@ -960,6 +984,11 @@ tcInferFun (L loc (HsVar name))
-- Don't wrap a context around a plain Id
; return (L loc fun, ty) }
+tcInferFun (L loc (HsSingleRecFld lbl name))
+ = do { (fun, ty) <- setSrcSpan loc (tcInferRecSelId lbl name)
+ -- Don't wrap a context around a plain Id
+ ; return (L loc fun, ty) }
+
tcInferFun fun
= do { (fun, fun_ty) <- tcInfer (tcMonoExpr fun)
@@ -1008,7 +1037,7 @@ tcSyntaxOp :: CtOrigin -> HsExpr Name -> TcType -> TcM (HsExpr TcId)
-- Typecheck a syntax operator, checking that it has the specified type
-- The operator is always a variable at this stage (i.e. renamer output)
-- This version assumes res_ty is a monotype
-tcSyntaxOp orig (HsVar op) res_ty = do { (expr, rho) <- tcInferIdWithOrig orig op
+tcSyntaxOp orig (HsVar op) res_ty = do { (expr, rho) <- tcInferIdWithOrig orig (nameRdrName op) op
; tcWrapResult expr rho res_ty }
tcSyntaxOp _ other _ = pprPanic "tcSyntaxOp" (ppr other)
\end{code}
@@ -1052,16 +1081,26 @@ tcCheckId name res_ty
; addErrCtxtM (funResCtxt False (HsVar name) actual_res_ty res_ty) $
tcWrapResult expr actual_res_ty res_ty }
+tcCheckRecSelId :: RdrName -> Name -> TcRhoType -> TcM (HsExpr TcId)
+tcCheckRecSelId lbl name res_ty
+ = do { (expr, actual_res_ty) <- tcInferRecSelId lbl name
+ ; addErrCtxtM (funResCtxt False (HsSingleRecFld lbl name) actual_res_ty res_ty) $
+ tcWrapResult expr actual_res_ty res_ty }
+
------------------------
tcInferId :: Name -> TcM (HsExpr TcId, TcRhoType)
-- Infer type, and deeply instantiate
-tcInferId n = tcInferIdWithOrig (OccurrenceOf n) n
+tcInferId n = tcInferIdWithOrig (OccurrenceOf n) (nameRdrName n) n
+
+tcInferRecSelId :: RdrName -> Name -> TcM (HsExpr TcId, TcRhoType)
+tcInferRecSelId lbl n = tcInferIdWithOrig (OccurrenceOfRecSel lbl) lbl n
------------------------
-tcInferIdWithOrig :: CtOrigin -> Name -> TcM (HsExpr TcId, TcRhoType)
+tcInferIdWithOrig :: CtOrigin -> RdrName -> Name ->
+ TcM (HsExpr TcId, TcRhoType)
-- Look up an occurrence of an Id, and instantiate it (deeply)
-tcInferIdWithOrig orig id_name
+tcInferIdWithOrig orig lbl id_name
= do { id <- lookup_id
; (id_expr, id_rho) <- instantiateOuter orig id
; (wrap, rho) <- deeplyInstantiate orig id_rho
@@ -1095,7 +1134,7 @@ tcInferIdWithOrig orig id_name
bad_patsyn name = ppr name <+> ptext (sLit "used in an expression, but it's a non-bidirectional pattern synonym")
check_naughty id
- | isNaughtyRecordSelector id = failWithTc (naughtyRecordSel id)
+ | isNaughtyRecordSelector id = failWithTc (naughtyRecordSel lbl)
| otherwise = return ()
------------------------
@@ -1354,6 +1393,136 @@ naughtiness in both branches. c.f. TcTyClsBindings.mkAuxBinds.
%* *
%************************************************************************
+\begin{code}
+getFixedTyVars :: [FieldLabelString] -> [TyVar] -> [DataCon] -> TyVarSet
+-- These tyvars must not change across the updates
+getFixedTyVars upd_fld_occs tvs1 cons
+ = mkVarSet [tv1 | con <- cons
+ , let (tvs, theta, arg_tys, _) = dataConSig con
+ flds = dataConFieldLabels con
+ fixed_tvs = exactTyVarsOfTypes fixed_tys
+ -- fixed_tys: See Note [Type of a record update]
+ `unionVarSet` tyVarsOfTypes theta
+ -- Universally-quantified tyvars that
+ -- appear in any of the *implicit*
+ -- arguments to the constructor are fixed
+ -- See Note [Implict type sharing]
+
+ fixed_tys = [ty | (fl, ty) <- zip flds arg_tys
+ , not (flLabel fl `elem` upd_fld_occs)]
+ , (tv1,tv) <- tvs1 `zip` tvs -- Discards existentials in tvs
+ , tv `elemVarSet` fixed_tvs ]
+\end{code}
+
+
+Note [Disambiguating record updates]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If the -XOverloadedRecordFields extension is used, the renamer may not
+be able to determine exactly which fields are being updated. Consider:
+
+ data S = MkS { foo :: Int }
+ data T = MkT { foo :: Int, bar :: Int }
+ data U = MkU { bar :: Int }
+
+ f x = x { foo = 3, bar = 2 }
+
+ g :: T -> T
+ g x = x { foo = 3 }
+
+ h x = (x :: T) { foo = 3 }
+
+In this situation, the renamer sees an update of `foo` but doesn't
+know which parent datatype is in use. In this case, the
+`hsRecFieldSel` field of the `HsRecField` stores a list of candidates
+as (parent, selector name) pairs. The disambiguateRecordBinds function
+tries to determine the parent in three ways:
+
+1. Check for types that have all the fields being updated. In the
+ example, `f` must be updating `T` because neither `S` nor `U` have
+ both fields. This may also discover that no suitable type exists.
+
+2. Use the type being pushed in, if it is already a TyConApp. Thus `g`
+ is obviously an update to `T`.
+
+3. Use the type signature of the record expression, if it exists and
+ is a TyConApp. Thus `h` is an update to `T`.
+
+We could add further tests, of a more heuristic nature. For example,
+rather than looking for an explicit signature, we could try to infer
+the type of the record expression, in case we are lucky enough to get
+a TyConApp straight away. However, it might be hard for programmers to
+predict whether a particular update is sufficiently obvious for the
+signature to be omitted.
+
+\begin{code}
+disambiguateRecordBinds :: LHsExpr Name -> HsRecFields Name a -> Type
+ -> TcM (HsRecFields Name a)
+disambiguateRecordBinds record_expr rbnds res_ty
+ | unambiguous = return rbnds -- Always the case if OverloadedRecordFields is off
+ | otherwise = do
+ { ps <- possibleParents orig_upd_flds
+ ; case ps of
+ [] -> failWithTc (noPossibleParents rbnds)
+ [p] -> chooseParent p rbnds
+ _ | Just p <- tyconOf res_ty -> chooseParent p rbnds
+ _ | Just sig_ty <- obviousSig (unLoc record_expr) ->
+ do { sig_tc_ty <- tcHsSigType ExprSigCtxt sig_ty
+ ; case tyconOf sig_tc_ty of
+ Just p -> chooseParent p rbnds
+ Nothing -> failWithTc badOverloadedUpdate }
+ _ -> failWithTc badOverloadedUpdate }
+ where
+ orig_upd_flds = hsRecFields rbnds
+ unambiguous = all (isLeft . snd) orig_upd_flds
+ tyconOf = fmap tyConName . tyConAppTyCon_maybe
+ isLeft = either (const True) (const False)
+
+ -- Calculate the list of possible parent tycons, by taking the
+ -- intersection of the possibilities for each field.
+ possibleParents :: [(FieldLabelString, Either Name [(Name, Name)])] -> RnM [Name]
+ possibleParents xs = fmap (foldr1 intersect) (mapM (parentsFor . snd) xs)
+
+ -- Unambiguous fields have a single possible parent: their actual
+ -- parent. Ambiguous fields record their possible parents for us.
+ parentsFor :: Either Name [(Name, Name)] -> RnM [Name]
+ parentsFor (Left name) = do { id <- tcLookupId name
+ ; ASSERT (isRecordSelector id)
+ return [tyConName (recordSelectorTyCon id)] }
+ parentsFor (Right xs) = return (map fst xs)
+
+ -- Make all the fields unambiguous by choosing the given parent.
+ -- Fails with an error if any of the ambiguous fields cannot have
+ -- that parent, e.g. if the user writes
+ -- r { x = e } :: T
+ -- where T does not have field x.
+ chooseParent :: Name -> HsRecFields Name arg -> RnM (HsRecFields Name arg)
+ chooseParent p rbnds | null orphans = return (rbnds { rec_flds = rec_flds' })
+ | otherwise = failWithTc (orphanFields p orphans)
+ where
+ (orphans, rec_flds') = partitionWith pickParent (rec_flds rbnds)
+
+ -- Returns Right fld' if fld can have parent p, or Left lbl if
+ -- not. For an unambigous field, we don't need to check again
+ -- that it has the correct parent, because possibleParents
+ -- will have returned that single parent.
+ pickParent :: HsRecField Name arg ->
+ Either (Located RdrName) (HsRecField Name arg)
+ pickParent fld@(HsRecField{ hsRecFieldSel = Left _ }) = Right fld
+ pickParent fld@(HsRecField{ hsRecFieldSel = Right xs })
+ = case lookup p xs of
+ Just name -> Right (fld{ hsRecFieldSel = Left name })
+ Nothing -> Left (hsRecFieldLbl fld)
+
+ -- A type signature on the record expression must be "obvious",
+ -- i.e. the outermost constructor ignoring parentheses.
+ obviousSig :: HsExpr Name -> Maybe (LHsType Name)
+ obviousSig (ExprWithTySig _ ty) = Just ty
+ obviousSig (HsPar p) = obviousSig (unLoc p)
+ obviousSig _ = Nothing
+
+\end{code}
+
+
Game plan for record bindings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Find the TyCon for the bindings, from the first field label.
@@ -1382,22 +1551,25 @@ tcRecordBinds data_con arg_tys (HsRecFields rbinds dd)
= do { mb_binds <- mapM do_bind rbinds
; return (HsRecFields (catMaybes mb_binds) dd) }
where
- flds_w_tys = zipEqual "tcRecordBinds" (dataConFieldLabels data_con) arg_tys
- do_bind fld@(HsRecField { hsRecFieldId = L loc field_lbl, hsRecFieldArg = rhs })
+ flds_w_tys = zipEqual "tcRecordBinds" (map flLabel $ dataConFieldLabels data_con) arg_tys
+ do_bind fld@(HsRecField { hsRecFieldLbl = L loc lbl, hsRecFieldSel = Left sel_name, hsRecFieldArg = rhs })
| Just field_ty <- assocMaybe flds_w_tys field_lbl
= addErrCtxt (fieldCtxt field_lbl) $
do { rhs' <- tcPolyExprNC rhs field_ty
- ; let field_id = mkUserLocal (nameOccName field_lbl)
- (nameUnique field_lbl)
+ ; let field_id = mkUserLocal (nameOccName sel_name)
+ (nameUnique sel_name)
field_ty loc
-- Yuk: the field_id has the *unique* of the selector Id
-- (so we can find it easily)
-- but is a LocalId with the appropriate type of the RHS
-- (so the desugarer knows the type of local binder to make)
- ; return (Just (fld { hsRecFieldId = L loc field_id, hsRecFieldArg = rhs' })) }
+ ; return (Just (fld { hsRecFieldSel = Left field_id, hsRecFieldArg = rhs' })) }
| otherwise
= do { addErrTc (badFieldCon (RealDataCon data_con) field_lbl)
; return Nothing }
+ where
+ field_lbl = occNameFS $ rdrNameOcc lbl
+ do_bind _ = panic "tcRecordBinds/do_bind: field with no selector"
checkMissingFields :: DataCon -> HsRecordBinds Name -> TcM ()
checkMissingFields data_con rbinds
@@ -1419,24 +1591,22 @@ checkMissingFields data_con rbinds
where
missing_s_fields
- = [ fl | (fl, str) <- field_info,
+ = [ flLabel fl | (fl, str) <- field_info,
isBanged str,
- not (fl `elem` field_names_used)
+ not (fl `elemField` field_names_used)
]
missing_ns_fields
- = [ fl | (fl, str) <- field_info,
+ = [ flLabel fl | (fl, str) <- field_info,
not (isBanged str),
- not (fl `elem` field_names_used)
+ not (fl `elemField` field_names_used)
]
- field_names_used = hsRecFields rbinds
+ field_names_used = hsRecFieldsUnambiguous rbinds
field_labels = dataConFieldLabels data_con
+ field_info = zipEqual "missingFields" field_labels field_strs
+ field_strs = dataConStrictMarks data_con
- field_info = zipEqual "missingFields"
- field_labels
- field_strs
-
- field_strs = dataConStrictMarks data_con
+ fl `elemField` flds = any (\ fl' -> flSelector fl == snd fl') flds
\end{code}
%************************************************************************
@@ -1454,7 +1624,7 @@ exprCtxt :: LHsExpr Name -> SDoc
exprCtxt expr
= hang (ptext (sLit "In the expression:")) 2 (ppr expr)
-fieldCtxt :: Name -> SDoc
+fieldCtxt :: FieldLabelString -> SDoc
fieldCtxt field_name
= ptext (sLit "In the") <+> quotes (ppr field_name) <+> ptext (sLit "field of a record")
@@ -1495,7 +1665,7 @@ funResCtxt has_args fun fun_res_ty env_ty tidy_env
Just (tc, _) -> isAlgTyCon tc
Nothing -> False
-badFieldTypes :: [(Name,TcType)] -> SDoc
+badFieldTypes :: [(FieldLabelString,TcType)] -> SDoc
badFieldTypes prs
= hang (ptext (sLit "Record update for insufficiently polymorphic field")
<> plural prs <> colon)
@@ -1521,7 +1691,7 @@ badFieldsUpd rbinds data_cons
-- Each field, together with a list indicating which constructors
-- have all the fields so far.
- growingSets :: [(Name, [Bool])]
+ growingSets :: [(FieldLabelString, [Bool])]
growingSets = scanl1 combine membership
combine (_, setMem) (field, fldMem)
= (field, zipWith (&&) setMem fldMem)
@@ -1534,13 +1704,13 @@ badFieldsUpd rbinds data_cons
(members, nonMembers) = partition (or . snd) membership
-- For each field, which constructors contain the field?
- membership :: [(Name, [Bool])]
+ membership :: [(FieldLabelString, [Bool])]
membership = sortMembership $
map (\fld -> (fld, map (Set.member fld) fieldLabelSets)) $
- hsRecFields rbinds
+ map (occNameFS . getOccName . snd) $ hsRecFieldsUnambiguous rbinds
- fieldLabelSets :: [Set.Set Name]
- fieldLabelSets = map (Set.fromList . dataConFieldLabels) data_cons
+ fieldLabelSets :: [Set.Set FieldLabelString]
+ fieldLabelSets = map (Set.fromList . map flLabel . dataConFieldLabels) data_cons
-- Sort in order of increasing number of True, so that a smaller
-- conflicting set can be found.
@@ -1576,7 +1746,7 @@ Finding the smallest subset is hard, so the code here makes
a decent stab, no more. See Trac #7989.
\begin{code}
-naughtyRecordSel :: TcId -> SDoc
+naughtyRecordSel :: RdrName -> SDoc
naughtyRecordSel sel_id
= ptext (sLit "Cannot use record selector") <+> quotes (ppr sel_id) <+>
ptext (sLit "as a function due to escaped type variables") $$
@@ -1586,7 +1756,7 @@ notSelector :: Name -> SDoc
notSelector field
= hsep [quotes (ppr field), ptext (sLit "is not a record selector")]
-missingStrictFields :: DataCon -> [FieldLabel] -> SDoc
+missingStrictFields :: DataCon -> [FieldLabelString] -> SDoc
missingStrictFields con fields
= header <> rest
where
@@ -1597,10 +1767,26 @@ missingStrictFields con fields
header = ptext (sLit "Constructor") <+> quotes (ppr con) <+>
ptext (sLit "does not have the required strict field(s)")
-missingFields :: DataCon -> [FieldLabel] -> SDoc
+missingFields :: DataCon -> [FieldLabelString] -> SDoc
missingFields con fields
= ptext (sLit "Fields of") <+> quotes (ppr con) <+> ptext (sLit "not initialised:")
<+> pprWithCommas ppr fields
-- callCtxt fun args = ptext (sLit "In the call") <+> parens (ppr (foldl mkHsApp fun args))
+
+noPossibleParents :: HsRecFields Name a -> SDoc
+noPossibleParents rbinds
+ = hang (ptext (sLit "No type has all these fields:"))
+ 2 (pprQuotedList fields)
+ where
+ fields = map fst (hsRecFields rbinds)
+
+badOverloadedUpdate :: SDoc
+badOverloadedUpdate = ptext (sLit "Record update is ambiguous, and requires a type signature")
+
+orphanFields :: Name -> [Located RdrName] -> SDoc
+orphanFields p flds
+ = hang (ptext (sLit "Type") <+> ppr p <+>
+ ptext (sLit "does not have field") <> plural flds <> colon)
+ 2 (pprQuotedList flds)
\end{code}