diff --git a/compiler/typecheck/Inst.hs b/compiler/typecheck/Inst.hs
index ace3e5313ec3e5d0ae40a9e8ea3828dc5f1ce2a8..2a17d7694dec27035ffd754221c19b36207ec8db 100644
--- a/compiler/typecheck/Inst.hs
+++ b/compiler/typecheck/Inst.hs
@@ -178,7 +178,7 @@ topInstantiate :: CtOrigin -> TcSigmaType -> TcM (HsWrapper, TcRhoType)
 -- if    topInstantiate ty = (wrap, rho)
 -- and   e :: ty
 -- then  wrap e :: rho  (that is, wrap :: ty "->" rho)
-topInstantiate = top_instantiate True (Just 0)
+topInstantiate = top_instantiate True (Just 0) False
 
 -- | Instantiate all outer 'Inferred' binders
 -- and any context. Never looks through arrows or specified type variables.
@@ -188,26 +188,27 @@ topInstantiateInferred :: CtOrigin -> TcSigmaType
 -- if    topInstantiate ty = (wrap, rho)
 -- and   e :: ty
 -- then  wrap e :: rho
-topInstantiateInferred = top_instantiate False (Just 0)
+topInstantiateInferred = top_instantiate False (Just 0) False
 
 -- | Instantiate all outer type variables
 -- and any context. Never looks through arrows.
 -- Takes guardedness of variables into account,
-topInstantiateGuarded :: Arity -> CtOrigin -> TcSigmaType -> TcM (HsWrapper, TcRhoType)
-topInstantiateGuarded n = top_instantiate True (Just n)
+topInstantiateGuarded :: Arity -> Bool -> CtOrigin -> TcSigmaType -> TcM (HsWrapper, TcRhoType)
+topInstantiateGuarded n ret_is_guarded = top_instantiate True (Just n) ret_is_guarded
 
 -- | Instantiate all outer type variables
 -- and any context. All unification variables become sigma's.
 topInstantiateSigma :: CtOrigin -> TcSigmaType -> TcM (HsWrapper, TcRhoType)
-topInstantiateSigma = top_instantiate True Nothing
+topInstantiateSigma = top_instantiate True Nothing True
 
 top_instantiate :: Bool   -- True  <=> instantiate *all* variables
                           -- False <=> instantiate only the inferred ones
                 -> Maybe Arity  -- number of provided arguments
-                                -- Just n  <=> n arguments where provided
+                                -- Just n  <=> n arguments were provided
                                 -- Nothing <=> instantiate everything as sigmas
+                -> Bool   -- True <=> consider vars in the return type as guarded
                 -> CtOrigin -> TcSigmaType -> TcM (HsWrapper, TcRhoType)
-top_instantiate inst_all prov_args orig ty
+top_instantiate inst_all prov_args ret_is_guarded orig ty
   | not (null binders && null theta)
   = do { let (inst_bndrs, leave_bndrs) = span should_inst binders
              (inst_theta, leave_theta)
@@ -240,7 +241,7 @@ top_instantiate inst_all prov_args orig ty
            if null leave_bndrs
 
          -- account for types like forall a. Num a => forall b. Ord b => ...
-           then top_instantiate inst_all prov_args orig sigma'
+           then top_instantiate inst_all prov_args ret_is_guarded orig sigma'
 
          -- but don't loop if there were any un-inst'able tyvars
            else return (idHsWrapper, sigma')
@@ -259,7 +260,11 @@ top_instantiate inst_all prov_args orig ty
     -- look at the prov_args first arguments for guardedness
     vars_which_are_guarded
       = let Just prov_args' = prov_args
-            args_to_look = take prov_args' (fst (splitFunTys rho))
+            (all_args, ret_type) = tcSplitFunTys rho
+            first_n_args = take prov_args' all_args
+            rest_of_args = drop prov_args' all_args ++ [ret_type]
+            should_take_ret = ret_is_guarded && length all_args >= prov_args'
+            args_to_look = first_n_args ++ if should_take_ret then rest_of_args else []
         in mapUnionVarSet guarded_vars args_to_look
 
     choice v
diff --git a/compiler/typecheck/TcExpr.hs b/compiler/typecheck/TcExpr.hs
index 77fe2ed7c05db0c9e112d68bd373550a56e06296..625fa453d57c69beea4f8bcdabf5ed9a4ec8d209 100644
--- a/compiler/typecheck/TcExpr.hs
+++ b/compiler/typecheck/TcExpr.hs
@@ -1294,7 +1294,7 @@ tcArgs fun orig_fun_ty fun_orig orig_args res_ty herald
 
     go _ _ fun_ty [] deferred_args
       | Check res_ty' <- res_ty
-      , isEmptyVarSet (unif_vars res_ty')
+      , res_ty_is_fully_known
       = do { wrap <- tcSubTypeO fun_orig GenSigCtxt fun_ty res_ty
            ; args' <- handle_args deferred_args
            ; return (wrap, args', res_ty')
@@ -1303,9 +1303,6 @@ tcArgs fun orig_fun_ty fun_orig orig_args res_ty herald
       = do { args' <- handle_args deferred_args
            ; return (idHsWrapper, args', fun_ty)
            }
-      where
-        unif_vars ty = filterVarSet (\tv -> isTcTyVar tv && not (isSkolemTyVar tv))
-                                    (exactTyCoVarsOfType ty)
 
     go acc_args n fun_ty (HsArgPar sp : args) deferred_args
       = do { let deferred_args' = deferred_args ++ [(HsArgPar sp, Nothing)]
@@ -1355,6 +1352,7 @@ tcArgs fun orig_fun_ty fun_orig orig_args res_ty herald
            ; (wrap, [arg_ty], res_ty)
                <- matchActualFunTysPart herald fun_orig (Just (unLoc fun)) 1 fun_ty
                                         acc_args orig_expr_args_arity next_val_args
+                                        res_ty_is_fully_known
                -- wrap :: fun_ty "->" arg_ty -> res_ty
            -- ; arg' <- tcArg fun arg arg_ty n  -- defer it until the end
            ; let defer_this_arg = (HsValArg arg, Just (arg_ty, n))
@@ -1368,6 +1366,15 @@ tcArgs fun orig_fun_ty fun_orig orig_args res_ty herald
         doc = text "When checking the" <+> speakNth n <+>
               text "argument to" <+> quotes (ppr fun)
 
+    res_ty_is_fully_known
+      | Check res_ty' <- res_ty
+      , isEmptyVarSet (unif_vars res_ty')
+      = True
+      | otherwise
+      = False
+      where unif_vars ty = filterVarSet (\tv -> isTcTyVar tv && not (isSkolemTyVar tv))
+                                        (exactTyCoVarsOfType ty)
+
     count_guarding_args [] = 0
     count_guarding_args (HsValArg _ : args) = 1 + count_guarding_args args
     count_guarding_args (HsArgPar _ : args) = count_guarding_args args
@@ -1391,7 +1398,8 @@ tcArgs fun orig_fun_ty fun_orig orig_args res_ty herald
            }
       | otherwise
       = do { args' <- handle_args args
-           ; arg'  <- tcArg fun arg arg_ty n
+           ; z_arg_ty <- zonkTcType arg_ty
+           ; arg'  <- tcArg fun arg z_arg_ty n
            ; return (HsValArg arg' : args')
            }
     handle_args (_ : _) = panic "tcArg/handle_arg"
diff --git a/compiler/typecheck/TcUnify.hs b/compiler/typecheck/TcUnify.hs
index 29dea953f949fd05120d4d4f4bca0165905833c7..3ee5bfc21bd5d31c999f52f132b6ccef662044f1 100644
--- a/compiler/typecheck/TcUnify.hs
+++ b/compiler/typecheck/TcUnify.hs
@@ -226,8 +226,8 @@ matchActualFunTys :: SDoc   -- See Note [Herald for matchExpectedFunTys]
                   -> TcM (HsWrapper, [TcSigmaType], TcSigmaType)
 -- If    matchActualFunTys n ty = (wrap, [t1,..,tn], ty_r)
 -- then  wrap : ty ~> (t1 -> ... -> tn -> ty_r)
-matchActualFunTys herald ct_orig mb_thing arity ty
-  = matchActualFunTysPart herald ct_orig mb_thing arity ty [] arity
+matchActualFunTys herald ct_orig mb_thing arity ty provided_args
+  = matchActualFunTysPart herald ct_orig mb_thing arity ty [] arity provided_args False
 
 -- | Variant of 'matchActualFunTys' that works when supplied only part
 -- (that is, to the right of some arrows) of the full function type
@@ -239,9 +239,10 @@ matchActualFunTysPart :: SDoc -- See Note [Herald for matchExpectedFunTys]
                       -> [TcSigmaType] -- reversed args. See (*) below.
                       -> Arity   -- overall arity of the function, for errs
                       -> Arity   -- how many arguments are provided explicitly
+                      -> Bool    -- whether the result type is fully known
                       -> TcM (HsWrapper, [TcSigmaType], TcSigmaType)
 matchActualFunTysPart herald ct_orig mb_thing arity orig_ty
-                      orig_old_args full_arity provided_args
+                      orig_old_args full_arity provided_args ret_is_known
   = go arity orig_old_args orig_ty provided_args
 -- Does not allocate unnecessary meta variables: if the input already is
 -- a function, we just take it apart.  Not only is this efficient,
@@ -278,7 +279,7 @@ matchActualFunTysPart herald ct_orig mb_thing arity orig_ty
 
     go n acc_args ty prov_args
       | not (null tvs && null theta)
-      = do { (wrap1, rho) <- topInstantiateGuarded prov_args ct_orig ty
+      = do { (wrap1, rho) <- topInstantiateGuarded prov_args ret_is_known ct_orig ty
            ; (wrap2, arg_tys, res_ty) <- go n acc_args rho prov_args
            ; return (wrap2 <.> wrap1, arg_tys, res_ty) }
       where