From 731e0fa7423ae34cf25bf967c90228ec7ea99e10 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benno=20F=C3=BCnfst=C3=BCck?= <benno.fuenfstueck@gmail.com>
Date: Wed, 19 Aug 2015 11:23:28 +0200
Subject: [PATCH] haskell: preserve overrideScope on override

We want code such as `(pkg.override {}).overrideScope (self: super: {})` to
work. This didn't work before, since `override` will call the original package
again, and the attribute `overideScope`, which `callPackageWithScope` added,
wasn't added again. The fix for this is to modify the package function itself
to include the `callPackageWithScope` attribute, so it'll be re-added whenever
the function is overriden for with arguments.

There is a small problem here though: since callPackage uses some magic
(`builtins.functionArgs`) to determine the auto-arguments of a function, we
can't just write `callPackageWith scope drvScope`, since
`builtins.functionArgs drvScope` will be `{}`. To fix this, we implement our own
`callPackageWith`.

Fixes https://github.com/NixOS/nixpkgs/issues/7953.
Closes https://github.com/NixOS/nixpkgs/pull/9336.
---
 .../haskell-modules/make-package-set.nix      | 20 ++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/pkgs/development/haskell-modules/make-package-set.nix b/pkgs/development/haskell-modules/make-package-set.nix
index 29b294619e6d..ee584b3c2ecb 100644
--- a/pkgs/development/haskell-modules/make-package-set.nix
+++ b/pkgs/development/haskell-modules/make-package-set.nix
@@ -44,9 +44,23 @@ self: let
 
   mkDerivation = makeOverridable mkDerivationImpl;
 
-  callPackageWithScope = scope: drv: args: (stdenv.lib.callPackageWith scope drv args) // {
-    overrideScope = f: callPackageWithScope (mkScope (fix' (extends f scope.__unfix__))) drv args;
-  };
+  callPackageWithScope = scope: fn: manualArgs:
+    let
+      # this code is copied from callPackage in lib/customisation.nix
+      #
+      # we cannot use `callPackage` here because we want to call `makeOverridable`
+      # on `drvScope` (we cannot add `overrideScope` after calling `callPackage` because then it is
+      # lost on `.override`) but determine the auto-args based on `drv` (the problem here
+      # is that nix has no way to "passthrough" args while preserving the reflection
+      # info that callPackage uses to determine the arguments).
+      drv = if builtins.isFunction fn then fn else import fn;
+      auto = builtins.intersectAttrs (builtins.functionArgs drv) scope;
+      drvScope = allArgs: drv allArgs // {
+        overrideScope = f:
+          let newScope = mkScope (fix' (extends f scope.__unfix__));
+          in callPackageWithScope newScope drv manualArgs;
+      };
+    in stdenv.lib.makeOverridable drvScope (auto // manualArgs);
 
   mkScope = scope: pkgs // pkgs.xorg // pkgs.gnome2 // scope;
   defaultScope = mkScope self;