- -- !!!TODO: Handle the `ats' parameter!!! -=chak
- = -- Prime error recovery, set source location
- recoverM (returnM Nothing) $
- setSrcSpan loc $
- addErrCtxt (instDeclCtxt1 poly_ty) $
-
- do { is_boot <- tcIsHsBoot
- ; checkTc (not is_boot || (isEmptyLHsBinds binds && null uprags))
- badBootDeclErr
-
- -- Typecheck the instance type itself. We can't use
- -- tcHsSigType, because it's not a valid user type.
- ; kinded_ty <- kcHsSigType poly_ty
- ; poly_ty' <- tcHsKindedType kinded_ty
- ; let (tyvars, theta, tau) = tcSplitSigmaTy poly_ty'
-
- ; (clas, inst_tys) <- checkValidInstHead tau
- ; checkValidInstance tyvars theta clas inst_tys
-
- ; dfun_name <- newDFunName clas inst_tys (srcSpanStart loc)
- ; overlap_flag <- getOverlapFlag
- ; let dfun = mkDictFunId dfun_name tyvars theta clas inst_tys
- ispec = mkLocalInstance dfun overlap_flag
-
- ; return (Just (InstInfo { iSpec = ispec, iBinds = VanillaInst binds uprags })) }
+ = -- Prime error recovery, set source location
+ recoverM (return ([], [])) $
+ setSrcSpan loc $
+ addErrCtxt (instDeclCtxt1 poly_ty) $
+
+ do { is_boot <- tcIsHsBoot
+ ; checkTc (not is_boot || (isEmptyLHsBinds binds && null uprags))
+ badBootDeclErr
+
+ ; (tyvars, theta, tau) <- tcHsInstHead poly_ty
+
+ -- Next, process any associated types.
+ ; idx_tycons <- mapM tcFamInstDecl ats
+
+ -- Now, check the validity of the instance.
+ ; (clas, inst_tys) <- checkValidInstHead tau
+ ; checkValidInstance tyvars theta clas inst_tys
+ ; checkValidAndMissingATs clas (tyvars, inst_tys)
+ (zip ats idx_tycons)
+
+ -- Finally, construct the Core representation of the instance.
+ -- (This no longer includes the associated types.)
+ ; dfun_name <- newDFunName clas inst_tys loc
+ ; overlap_flag <- getOverlapFlag
+ ; let (eq_theta,dict_theta) = partition isEqPred theta
+ theta' = eq_theta ++ dict_theta
+ dfun = mkDictFunId dfun_name tyvars theta' clas inst_tys
+ ispec = mkLocalInstance dfun overlap_flag
+
+ ; return ([InstInfo { iSpec = ispec,
+ iBinds = VanillaInst binds uprags }],
+ catMaybes idx_tycons)
+ }
+ where
+ -- We pass in the source form and the type checked form of the ATs. We
+ -- really need the source form only to be able to produce more informative
+ -- error messages.
+ checkValidAndMissingATs :: Class
+ -> ([TyVar], [TcType]) -- instance types
+ -> [(LTyClDecl Name, -- source form of AT
+ Maybe TyThing)] -- Core form of AT
+ -> TcM ()
+ checkValidAndMissingATs clas inst_tys ats
+ = do { -- Issue a warning for each class AT that is not defined in this
+ -- instance.
+ ; let class_ats = map tyConName (classATs clas)
+ defined_ats = listToNameSet . map (tcdName.unLoc.fst) $ ats
+ omitted = filterOut (`elemNameSet` defined_ats) class_ats
+ ; warn <- doptM Opt_WarnMissingMethods
+ ; mapM_ (warnTc warn . omittedATWarn) omitted
+
+ -- Ensure that all AT indexes that correspond to class parameters
+ -- coincide with the types in the instance head. All remaining
+ -- AT arguments must be variables. Also raise an error for any
+ -- type instances that are not associated with this class.
+ ; mapM_ (checkIndexes clas inst_tys) ats
+ }
+
+ checkIndexes _ _ (hsAT, Nothing) =
+ return () -- skip, we already had an error here
+ checkIndexes clas inst_tys (hsAT, Just (ATyCon tycon)) =
+-- !!!TODO: check that this does the Right Thing for indexed synonyms, too!
+ checkIndexes' clas inst_tys hsAT
+ (tyConTyVars tycon,
+ snd . fromJust . tyConFamInst_maybe $ tycon)
+ checkIndexes _ _ _ = panic "checkIndexes"
+
+ checkIndexes' clas (instTvs, instTys) hsAT (atTvs, atTys)
+ = let atName = tcdName . unLoc $ hsAT
+ in
+ setSrcSpan (getLoc hsAT) $
+ addErrCtxt (atInstCtxt atName) $
+ case find ((atName ==) . tyConName) (classATs clas) of
+ Nothing -> addErrTc $ badATErr clas atName -- not in this class
+ Just atDecl ->
+ case assocTyConArgPoss_maybe atDecl of
+ Nothing -> panic "checkIndexes': AT has no args poss?!?"
+ Just poss ->
+
+ -- The following is tricky! We need to deal with three
+ -- complications: (1) The AT possibly only uses a subset of
+ -- the class parameters as indexes and those it uses may be in
+ -- a different order; (2) the AT may have extra arguments,
+ -- which must be type variables; and (3) variables in AT and
+ -- instance head will be different `Name's even if their
+ -- source lexemes are identical.
+ --
+ -- Re (1), `poss' contains a permutation vector to extract the
+ -- class parameters in the right order.
+ --
+ -- Re (2), we wrap the (permuted) class parameters in a Maybe
+ -- type and use Nothing for any extra AT arguments. (First
+ -- equation of `checkIndex' below.)
+ --
+ -- Re (3), we replace any type variable in the AT parameters
+ -- that has the same source lexeme as some variable in the
+ -- instance types with the instance type variable sharing its
+ -- source lexeme.
+ --
+ let relevantInstTys = map (instTys !!) poss
+ instArgs = map Just relevantInstTys ++
+ repeat Nothing -- extra arguments
+ renaming = substSameTyVar atTvs instTvs
+ in
+ zipWithM_ checkIndex (substTys renaming atTys) instArgs
+
+ checkIndex ty Nothing
+ | isTyVarTy ty = return ()
+ | otherwise = addErrTc $ mustBeVarArgErr ty
+ checkIndex ty (Just instTy)
+ | ty `tcEqType` instTy = return ()
+ | otherwise = addErrTc $ wrongATArgErr ty instTy
+
+ listToNameSet = addListToNameSet emptyNameSet
+
+ substSameTyVar [] _ = emptyTvSubst
+ substSameTyVar (tv:tvs) replacingTvs =
+ let replacement = case find (tv `sameLexeme`) replacingTvs of
+ Nothing -> mkTyVarTy tv
+ Just rtv -> mkTyVarTy rtv
+ --
+ tv1 `sameLexeme` tv2 =
+ nameOccName (tyVarName tv1) == nameOccName (tyVarName tv2)
+ in
+ extendTvSubst (substSameTyVar tvs replacingTvs) tv replacement