summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2016-03-01 20:47:08 +0100
committerEelco Dolstra <eelco.dolstra@logicblox.com>2016-03-01 20:52:06 +0100
commitf3d94cfc23a2787772a369e2ca9e0cd94e72b8b3 (patch)
tree2501bf5c09108c836925aefc4674ebec0b508193 /lib
parentbf4cafd1ddbd7c396a9df6a5d0fb02f2b7d21896 (diff)
downloadnixpkgs-f3d94cfc23a2787772a369e2ca9e0cd94e72b8b3.tar
nixpkgs-f3d94cfc23a2787772a369e2ca9e0cd94e72b8b3.tar.gz
nixpkgs-f3d94cfc23a2787772a369e2ca9e0cd94e72b8b3.tar.bz2
nixpkgs-f3d94cfc23a2787772a369e2ca9e0cd94e72b8b3.tar.lz
nixpkgs-f3d94cfc23a2787772a369e2ca9e0cd94e72b8b3.tar.xz
nixpkgs-f3d94cfc23a2787772a369e2ca9e0cd94e72b8b3.tar.zst
nixpkgs-f3d94cfc23a2787772a369e2ca9e0cd94e72b8b3.zip
Revert "Add the tool "nixos-typecheck" that can check an option declaration to:"
This reverts commit cad8957eabcbf73062226d28366fd446c15c8737. It
breaks NixOps, but more importantly, such major changes to the module
system really need to be reviewed.
Diffstat (limited to 'lib')
-rw-r--r--lib/modules.nix99
-rw-r--r--lib/options.nix145
-rw-r--r--lib/types.nix217
3 files changed, 86 insertions, 375 deletions
diff --git a/lib/modules.nix b/lib/modules.nix
index d08dc9f85a2..12ec7004d1e 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -23,6 +23,8 @@ rec {
                   specialArgs ? {}
                 , # This would be remove in the future, Prefer _module.args option instead.
                   args ? {}
+                , # This would be remove in the future, Prefer _module.check option instead.
+                  check ? true
                 }:
     let
       # This internal module declare internal options under the `_module'
@@ -43,22 +45,9 @@ rec {
           _module.check = mkOption {
             type = types.bool;
             internal = true;
-            default = true;
+            default = check;
             description = "Whether to check whether all option definitions have matching declarations.";
           };
-
-          _module.typeInference = mkOption {
-            type = types.nullOr types.str;
-            internal = true;
-            default = null; # TODO: Move away from 'null' after enough testing.
-            description = ''
-              Mode of type inferencing. Possible values are:
-              null = Disable type inferencing completely. Use 'types.unspecified' for every option without type definition.
-              "silent" = Try to infer type of option without type definition, but do not print anything.
-              "printUnspecified" = Try to infer type of option without type definition and print options for which no full type could be inferred.
-              "printAll" = Try to infer type of option without type definition and print all options without type definition.
-            '';
-          };
         };
 
         config = {
@@ -71,7 +60,7 @@ rec {
       # Note: the list of modules is reversed to maintain backward
       # compatibility with the old module system.  Not sure if this is
       # the most sensible policy.
-      options = mergeModules (config._module) prefix (reverseList closed);
+      options = mergeModules prefix (reverseList closed);
 
       # Traverse options and extract the option values into the final
       # config set.  At the same time, check whether all option
@@ -181,11 +170,11 @@ rec {
      At the same time, for each option declaration, it will merge the
      corresponding option definitions in all machines, returning them
      in the ‘value’ attribute of each option. */
-  mergeModules = _module: prefix: modules:
-    mergeModules' _module prefix modules
+  mergeModules = prefix: modules:
+    mergeModules' prefix modules
       (concatMap (m: map (config: { inherit (m) file; inherit config; }) (pushDownProperties m.config)) modules);
 
-  mergeModules' = _module: prefix: options: configs:
+  mergeModules' = prefix: options: configs:
     listToAttrs (map (name: {
       # We're descending into attribute ‘name’.
       inherit name;
@@ -211,8 +200,8 @@ rec {
             (filter (m: m.config ? ${name}) configs);
         in
           if nrOptions == length decls then
-            let opt = fixupOptionType _module.typeInference loc (mergeOptionDecls loc decls);
-            in evalOptionValue _module loc opt defns'
+            let opt = fixupOptionType loc (mergeOptionDecls loc decls);
+            in evalOptionValue loc opt defns'
           else if nrOptions != 0 then
             let
               firstOption = findFirst (m: isOption m.options) "" decls;
@@ -220,7 +209,7 @@ rec {
             in
               throw "The option `${showOption loc}' in `${firstOption.file}' is a prefix of options in `${firstNonOption.file}'."
           else
-            mergeModules' _module loc decls defns;
+            mergeModules' loc decls defns;
     }) (concatMap (m: attrNames m.options) options))
     // { _definedNames = map (m: { inherit (m) file; names = attrNames m.config; }) configs; };
 
@@ -269,7 +258,7 @@ rec {
 
   /* Merge all the definitions of an option to produce the final
      config value. */
-  evalOptionValue = _module: loc: opt: defs:
+  evalOptionValue = loc: opt: defs:
     let
       # Add in the default value for this option, if any.
       defs' =
@@ -281,7 +270,7 @@ rec {
         if opt.readOnly or false && length defs' > 1 then
           throw "The option `${showOption loc}' is read-only, but it's set multiple times."
         else
-          mergeDefinitions _module loc opt.type defs';
+          mergeDefinitions loc opt.type defs';
 
       # Check whether the option is defined, and apply the ‘apply’
       # function to the merged value.  This allows options to yield a
@@ -302,7 +291,7 @@ rec {
       };
 
   # Merge definitions of a value of a given type.
-  mergeDefinitions = _module: loc: type: defs: rec {
+  mergeDefinitions = loc: type: defs: rec {
     defsFinal =
       let
         # Process mkMerge and mkIf properties.
@@ -325,7 +314,7 @@ rec {
     mergedValue = foldl' (res: def:
       if type.check def.value then res
       else throw "The option value `${showOption loc}' in `${def.file}' is not a ${type.name}.")
-      (type.merge _module loc defsFinal) defsFinal;
+      (type.merge loc defsFinal) defsFinal;
 
     isDefined = defsFinal != [];
 
@@ -423,7 +412,7 @@ rec {
   /* Hack for backward compatibility: convert options of type
      optionSet to options of type submodule.  FIXME: remove
      eventually. */
-  fixupOptionType = typeInference: loc: opt:
+  fixupOptionType = loc: opt:
     let
       options = opt.options or
         (throw "Option `${showOption loc'}' has type optionSet but has no option attribute, in ${showFiles opt.declarations}.");
@@ -435,66 +424,12 @@ rec {
         else if tp.name == "list of option sets" then types.listOf (types.submodule options)
         else if tp.name == "null or option set" then types.nullOr (types.submodule options)
         else tp;
-
     in
       if opt.type.getSubModules or null == null
-      then opt // { type = f (opt.type or (inferType typeInference loc opt)); }
+      then opt // { type = f (opt.type or types.unspecified); }
       else opt // { type = opt.type.substSubModules opt.options; options = []; };
 
 
-  /* Function that tries to infer the type of an option from the default value of the option. */
-  inferType = mode: loc: opt:
-    let
-      doc = x: elemAt x 0;
-      type = x: elemAt x 1;
-      containsUnspecified = x: elemAt x 2;
-      inferType' = def:
-        if isDerivation def then [ "package" types.package false ]
-        else if isBool def then [ "bool" types.bool false ]
-        else if builtins.isString def then [ "str" types.str false ]
-        else if isInt def then [ "int" types.int false ]
-        else if isFunction def then [ "functionTo unspecified" (types.functionTo types.unspecified) true ]
-        else if isList def then
-                let nestedType = if (length def > 0) && (all (x: (type (inferType' x)) == (type (inferType' (head def)))) def)
-                                 then inferType' (head def)
-                                 else [ "unspecified" types.unspecified true ];
-                in [ "listOf ${doc nestedType}" (types.listOf (type nestedType)) (containsUnspecified nestedType) ]
-        else if isAttrs def then
-                let list = mapAttrsToList (_: v: v) (removeAttrs def ["_args"]);
-                    nestedType = if (length list > 0) && (all (x: (type (inferType' x)) == (type (inferType' (head list)))) list)
-                                 then inferType' (head list)
-                                 else [ "unspecified" types.unspecified true ];
-                in [ "attrsOf ${doc nestedType}" (types.attrsOf (type nestedType)) (containsUnspecified nestedType) ]
-        else [ "unspecified" types.unspecified true ];
-
-      inferDoc = x: ''
-        Inferring the type of "${showOption loc}" to "${doc x}".
-        Please verify the inferred type and define the type explicitely in ${showFiles opt.declarations}!
-      '';
-
-      inferredType = printMode:
-        let inferred = inferType' opt.default;
-        in if printMode == "silent" then type inferred
-           else if printMode == "printAll" then builtins.trace (inferDoc inferred) (type inferred)
-           else if printMode == "printUnspecified" && (containsUnspecified inferred) then builtins.trace (inferDoc inferred) (type inferred)
-           else type inferred;
-
-      noInferDoc = ''
-        Could not infer a type for "${showOption loc}", using "unspecified" instead.
-        Please define the type explicitely in ${showFiles opt.declarations}!
-      '';
-
-      hasDefault = (opt ? default) && !(opt ? defaultText);
-      isExternalVisible = (opt.visible or true) && !(opt.internal or false);
-    in
-
-    if isNull mode || !isExternalVisible
-    then types.unspecified
-    else if hasDefault
-         then inferredType mode /* Set to 'true' to see every type that is being inferred, not just those types that result in 'unspecified'. */
-         else if mode != "silent" then builtins.trace noInferDoc types.unspecified else types.unspecified;
-
-
   /* Properties. */
 
   mkIf = condition: content:
@@ -562,7 +497,7 @@ rec {
 
 
   /* Compatibility. */
-  fixMergeModules = modules: args: evalModules { inherit args; modules = (modules ++ [{ _module.check = false; }]); };
+  fixMergeModules = modules: args: evalModules { inherit modules args; check = false; };
 
 
   /* Return a module that causes a warning to be shown if the
diff --git a/lib/options.nix b/lib/options.nix
index d6876e18fe4..444ec37e6ea 100644
--- a/lib/options.nix
+++ b/lib/options.nix
@@ -6,7 +6,6 @@ with import ./trivial.nix;
 with import ./lists.nix;
 with import ./attrsets.nix;
 with import ./strings.nix;
-with {inherit (import ./types.nix) types; };
 
 rec {
 
@@ -43,17 +42,16 @@ rec {
     description = "Sink for option definitions.";
     type = mkOptionType {
       name = "sink";
-      typerep = "(sink)";
       check = x: true;
-      merge = config: loc: defs: false;
+      merge = loc: defs: false;
     };
     apply = x: throw "Option value is not readable because the option is not declared.";
   } // attrs);
 
-  mergeDefaultOption = config: loc: defs:
+  mergeDefaultOption = loc: defs:
     let list = getValues defs; in
     if length list == 1 then head list
-    else if all isFunction list then x: mergeDefaultOption config loc (map (f: f x) list)
+    else if all isFunction list then x: mergeDefaultOption loc (map (f: f x) list)
     else if all isList list then concatLists list
     else if all isAttrs list then foldl' lib.mergeAttrs {} list
     else if all isBool list then foldl' lib.or false list
@@ -61,14 +59,14 @@ rec {
     else if all isInt list && all (x: x == head list) list then head list
     else throw "Cannot merge definitions of `${showOption loc}' given in ${showFiles (getFiles defs)}.";
 
-  mergeOneOption = config: loc: defs:
+  mergeOneOption = loc: defs:
     if defs == [] then abort "This case should never happen."
     else if length defs != 1 then
       throw "The unique option `${showOption loc}' is defined multiple times, in ${showFiles (getFiles defs)}."
     else (head defs).value;
 
   /* "Merge" option definitions by checking that they all have the same value. */
-  mergeEqualOption = config: loc: defs:
+  mergeEqualOption = loc: defs:
     if defs == [] then abort "This case should never happen."
     else foldl' (val: def:
       if def.value != val then
@@ -79,154 +77,53 @@ rec {
   getValues = map (x: x.value);
   getFiles = map (x: x.file);
 
+
   # Generate documentation template from the list of option declaration like
   # the set generated with filterOptionSets.
   optionAttrSetToDocList = optionAttrSetToDocList' [];
 
-  optionAttrSetToDocList' = prefix: internalModuleConfig: options:
+  optionAttrSetToDocList' = prefix: options:
     concatMap (opt:
       let
-        decls = filter (x: x != unknownModule) opt.declarations;
         docOption = rec {
           name = showOption opt.loc;
           description = opt.description or (throw "Option `${name}' has no description.");
-          declarations = decls;
+          declarations = filter (x: x != unknownModule) opt.declarations;
           internal = opt.internal or false;
           visible = opt.visible or true;
           readOnly = opt.readOnly or false;
           type = opt.type.name or null;
         }
-        // (if opt ? example then { example = detectDerivation decls opt.example; } else {})
-        // (if opt ? default then { default = detectDerivation decls opt.default; } else {})
+        // (if opt ? example then { example = scrubOptionValue opt.example; } else {})
+        // (if opt ? default then { default = scrubOptionValue opt.default; } else {})
         // (if opt ? defaultText then { default = opt.defaultText; } else {});
 
         subOptions =
-          let ss = opt.type.getSubOptionsPrefixed opt.loc;
-          in if ss != {} then optionAttrSetToDocList' opt.loc internalModuleConfig (ss internalModuleConfig) else [];
+          let ss = opt.type.getSubOptions opt.loc;
+          in if ss != {} then optionAttrSetToDocList' opt.loc ss else [];
       in
         [ docOption ] ++ subOptions) (collect isOption options);
 
-  # TODO: Use "extractOptionAttrSet" instead of "optionAttrSetToDocList'" to reduce the code size.
-  #       It should be a drop-in-replacement. But first, examine the impact on the evaluation time.
-  # optionAttrSetToDocList = extractOptionAttrSet true [];
-
-  # Generate a machine readable specification of the list of option declarations.
-  optionAttrSetToParseableSpecifications = extractOptionAttrSet false [];
-
-  extractOptionAttrSet = toDoc: prefix: internalModuleConfig: options:
-    concatMap (opt:
-      let
-        optionName = showOption opt.loc;
-
-        # Check if a type contains derivations, that is check if a type nests
-        # a 'package', 'packageSet' or 'nixpkgsConfig' type.
-        hasDerivation = any (t: elem t opt.type.nestedTypes) ((map (x: x.typerep) (with types; [package packageSet])) ++ ["(nixpkgsConfig)"]);
-
-        # Check if type is 'path' which can potentially contain a derivation.
-        maybeHiddenDerivation = any (t: elem t opt.type.nestedTypes) (map (x: x.typerep) (with types; [path]));
-
-        isDefaultValue = elem opt.default opt.type.defaultValues;
-
-        /* Enforce that the example attribute is wrapped with 'literalExample'
-           for every type that contains derivations. */
-        example =
-          if opt ? example
-          then (if hasDerivation
-                then (if isLiteralExample opt.example
-                      then { example = detectDerivation decls opt.example; }
-                      else throw "The attribute ${optionName}.example must be wrapped with 'literalExample' in ${concatStringsSep " and " decls}!")
-                else { example = detectDerivation decls opt.example; })
-          else {};
-
-        /* Enforce that the 'defaultText' attribute is defined for every option
-           that has a 'default' attribute that contains derivations. */
-        default =
-          if opt ? default
-          then (if hasDerivation
-                then (if isDefaultValue
-                      then { default = opt.default; }
-                      else (if opt ? defaultText
-                            then { default = literalExample (detectDerivation decls opt.defaultText); }
-                            else throw "The option ${optionName} requires a 'defaultText' attribute in ${concatStringsSep " and " decls}!"))
-                else (if opt ? defaultText
-                      then (if maybeHiddenDerivation
-                            then (if (let eval = builtins.tryEval (findDerivation opt.default); in eval.success && !eval.value)
-                                  then builtins.trace
-                                       "The attribute ${optionName}.defaultText might not be necessary in ${concatStringsSep " and " decls}!"
-                                       { default = literalExample (detectDerivation decls opt.defaultText); }
-                                  else { default = literalExample (detectDerivation decls opt.defaultText); })
-                            else builtins.trace
-                                 "The attribute ${optionName}.defaultText is not used and can be removed in ${concatStringsSep " and " decls}!"
-                                 { default = detectDerivation decls opt.default; })
-                      else { default = detectDerivation decls opt.default; }))
-          else {};
-
-        decls = filter (x: x != unknownModule) opt.declarations;
-
-        docOption = {
-          name = optionName;
-          description = opt.description or (throw "Option `${optionName}' has no description.");
-          declarations = decls;
-          internal = opt.internal or false;
-          visible = opt.visible or true;
-          readOnly = opt.readOnly or false;
-        } // example // default // subOptions // typeKeys;
-
-        typeKeys = if toDoc then { type = opt.type.name or null; } else { type = opt.type.typerep; keys = opt.loc; };
 
-        subOptions =
-          if toDoc
-          then {}
-          else let ss = opt.type.getSubOptions;
-               in if ss != {} then { suboptions = (extractOptionAttrSet false [] internalModuleConfig (ss internalModuleConfig)); } else {};
-
-        subOptionsDoc =
-          if toDoc
-          then let ss = opt.type.getSubOptionsPrefixed opt.loc;
-               in if ss != {} then extractOptionAttrSet true opt.loc internalModuleConfig (ss internalModuleConfig) else []
-          else [];
-      in
-        [ docOption ]  ++ subOptionsDoc )
-          (filter (opt: (opt.visible or true) && !(opt.internal or false)) (collect isOption options));
-
-
-  /* This function recursively checks for derivations within an
-     an expression, and throws an error if a derivation or a
-     store path is found. The function is used to ensure that no
-     derivation leaks from the 'default' or 'example' attributes
-     of an option.
-     This makes the generation of `options.xml' much more efficient:
-     the XML representation of derivations is very large (on the
-     order of megabytes) and is not actually used by the manual
-     generator. */
-  detectDerivation = decl: x:
+  /* This function recursively removes all derivation attributes from
+     `x' except for the `name' attribute.  This is to make the
+     generation of `options.xml' much more efficient: the XML
+     representation of derivations is very large (on the order of
+     megabytes) and is not actually used by the manual generator. */
+  scrubOptionValue = x:
     if isDerivation x then
-      throw "Found unexpected derivation in '${x.name}' in '${concatStringsSep " and " decl}'!"
-    else if isString x && isStorePath x then
-      throw "Found unexpected store path in '${x.name}' in '${concatStringsSep " and " decl}'!"
-    else if isList x then map (detectDerivation decl) x
-    else if isAttrs x then mapAttrs (n: v: (detectDerivation decl) v) (removeAttrs x ["_args"])
+      { type = "derivation"; drvPath = x.name; outPath = x.name; name = x.name; }
+    else if isList x then map scrubOptionValue x
+    else if isAttrs x then mapAttrs (n: v: scrubOptionValue v) (removeAttrs x ["_args"])
     else x;
 
-  /* Same as detectDerivation, but returns a boolean instead of
-     throwing an exception. */
-  findDerivation = x:
-    if (isString x && isStorePath x) || isDerivation x then true
-    else if isList x then any findDerivation x
-    else if isAttrs x then any findDerivation (mapAttrsToList (_: v: v) (removeAttrs x ["_args"]))
-    else false;
-
-
 
   /* For use in the ‘example’ option attribute.  It causes the given
      text to be included verbatim in documentation.  This is necessary
      for example values that are not simple values, e.g.,
      functions. */
-  # TODO: A more general name would probably be "literalNix".
   literalExample = text: { _type = "literalExample"; inherit text; };
 
-  isLiteralExample = x: isAttrs x && hasAttr "_type" x && x._type == "literalExample";
-
 
   /* Helper functions. */
   showOption = concatStringsSep ".";
diff --git a/lib/types.nix b/lib/types.nix
index 385103d4214..b4d29ac84d2 100644
--- a/lib/types.nix
+++ b/lib/types.nix
@@ -1,8 +1,6 @@
 # Definitions related to run-time type checking.  Used in particular
 # to type-check NixOS configurations.
 
-let lib = import ./default.nix; in
-
 with import ./lists.nix;
 with import ./attrsets.nix;
 with import ./options.nix;
@@ -23,8 +21,6 @@ rec {
   mkOptionType =
     { # Human-readable representation of the type.
       name
-    , # Parseable representation of the type.
-      typerep
     , # Function applied to each definition that should return true if
       # its type-correct, false otherwise.
       check ? (x: true)
@@ -35,59 +31,40 @@ rec {
       # definition values and locations (e.g. [ { file = "/foo.nix";
       # value = 1; } { file = "/bar.nix"; value = 2 } ]).
       merge ? mergeDefaultOption
-    , # Return list of sub-options.
-      getSubOptions ? {}
-    , # Same as 'getSubOptions', but with extra information about the
-      # location of the option which is used to generate documentation.
-      getSubOptionsPrefixed ? null
+    , # Return a flat list of sub-options.  Used to generate
+      # documentation.
+      getSubOptions ? prefix: {}
     , # List of modules if any, or null if none.
       getSubModules ? null
     , # Function for building the same option type  with a different list of
       # modules.
       substSubModules ? m: null
-    , # List of type representations (typerep) of all the elementary types
-      # that are nested within the type. For an elementary type the list is
-      # a singleton of the typerep of itself.
-      # NOTE: Must be specified for every container type!
-      nestedTypes ? null
-    , # List of all default values, and an empty list if no default value exists.
-      defaultValues ? []
     }:
     { _type = "option-type";
-      inherit name typerep check merge getSubOptions getSubModules substSubModules defaultValues;
-      nestedTypes = if (isNull nestedTypes) then (singleton typerep) else nestedTypes;
-      getSubOptionsPrefixed = if (isNull getSubOptionsPrefixed) then (prefix: getSubOptions) else getSubOptionsPrefixed;
+      inherit name check merge getSubOptions getSubModules substSubModules;
     };
 
 
   types = rec {
 
-    #
-    # Elementary types
-    #
-
     unspecified = mkOptionType {
       name = "unspecified";
-      typerep = "(unspecified)";
     };
 
     bool = mkOptionType {
       name = "boolean";
-      typerep = "(boolean)";
       check = isBool;
       merge = mergeEqualOption;
     };
 
     int = mkOptionType {
       name = "integer";
-      typerep = "(integer)";
       check = isInt;
       merge = mergeOneOption;
     };
 
     str = mkOptionType {
       name = "string";
-      typerep = "(string)";
       check = isString;
       merge = mergeOneOption;
     };
@@ -95,111 +72,73 @@ rec {
     # Merge multiple definitions by concatenating them (with the given
     # separator between the values).
     separatedString = sep: mkOptionType {
-      name = "string" + (optionalString (sep != "") " separated by ${sep}");
-      typerep = "(separatedString(${escape ["(" ")"] sep}))";
+      name = "string";
       check = isString;
-      merge = _module: loc: defs: concatStringsSep sep (getValues defs);
+      merge = loc: defs: concatStringsSep sep (getValues defs);
     };
 
-    lines = separatedString "\n" // { typerep = "(lines)"; };
-    commas = separatedString "," // { typerep = "(commas)"; };
-    envVar = separatedString ":" // { typerep = "(envVar)"; };
+    lines = separatedString "\n";
+    commas = separatedString ",";
+    envVar = separatedString ":";
 
     # Deprecated; should not be used because it quietly concatenates
     # strings, which is usually not what you want.
-    string = separatedString "" // { typerep = "(string)"; };
+    string = separatedString "";
 
     attrs = mkOptionType {
       name = "attribute set";
-      typerep = "(attrs)";
       check = isAttrs;
-      merge = _module: loc: foldl' (res: def: mergeAttrs res def.value) {};
+      merge = loc: foldl' (res: def: mergeAttrs res def.value) {};
     };
 
     # derivation is a reserved keyword.
     package = mkOptionType {
       name = "package";
-      typerep = "(package)";
       check = x: isDerivation x || isStorePath x;
-      merge = _module: loc: defs:
-        let res = mergeOneOption _module loc defs;
+      merge = loc: defs:
+        let res = mergeOneOption loc defs;
         in if isDerivation res then res else toDerivation res;
     };
 
-    # The correct type of packageSet would be:
-    # packageSet = attrsOf (either package packageSet)
-    # (Not sure if nix would allow to define a recursive type.)
-    # However, currently it is not possible to check that a packageSet actually
-    # contains packages (that is derivations). The check 'isDerivation' is too
-    # eager for the current implementation of the assertion mechanism and of the
-    # licenses control mechanism. That means it is not generally possible to go
-    # into the attribute set of packages to check that every attribute would
-    # evaluate to a derivation if the package would actually be evaluated. Maybe
-    # that restriction can be lifted in the future, but for now the content of
-    # the packageSet is not checked.
-    # TODO: The 'merge' function is copied from 'mergeDefaultOption' to keep
-    # backwards compatibility with the 'unspecified' type that was used for
-    # package sets previously. Maybe review if the merge function has to change.
-    packageSet = mkOptionType {
-      name = "derivation set";
-      typerep = "(packageSet)";
-      check = isAttrs;
-      merge = _module: loc: defs: foldl' mergeAttrs {} (map (x: x.value) defs);
-    };
-
     path = mkOptionType {
       name = "path";
-      typerep = "(path)";
       # Hacky: there is no ‘isPath’ primop.
       check = x: builtins.substring 0 1 (toString x) == "/";
       merge = mergeOneOption;
     };
 
-
-    #
-    # Container types
-    #
-
     # drop this in the future:
     list = builtins.trace "`types.list' is deprecated; use `types.listOf' instead" types.listOf;
 
     listOf = elemType: mkOptionType {
       name = "list of ${elemType.name}s";
-      typerep = "(listOf${elemType.typerep})";
       check = isList;
-      merge = _module: loc: defs:
+      merge = loc: defs:
         map (x: x.value) (filter (x: x ? value) (concatLists (imap (n: def: imap (m: def':
-            (mergeDefinitions _module
+            (mergeDefinitions
               (loc ++ ["[definition ${toString n}-entry ${toString m}]"])
               elemType
               [{ inherit (def) file; value = def'; }]
             ).optionalValue
           ) def.value) defs)));
-      getSubOptions = elemType.getSubOptions;
-      getSubOptionsPrefixed = prefix: elemType.getSubOptionsPrefixed (prefix ++ ["*"]);
+      getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
       getSubModules = elemType.getSubModules;
       substSubModules = m: listOf (elemType.substSubModules m);
-      nestedTypes = elemType.nestedTypes;
-      defaultValues = [[]];
     };
 
     attrsOf = elemType: mkOptionType {
       name = "attribute set of ${elemType.name}s";
-      typerep = "(attrsOf${elemType.typerep})";
       check = isAttrs;
-      merge = _module: loc: defs:
+      merge = loc: defs:
         mapAttrs (n: v: v.value) (filterAttrs (n: v: v ? value) (zipAttrsWith (name: defs:
-            (mergeDefinitions _module (loc ++ [name]) elemType defs).optionalValue
+            (mergeDefinitions (loc ++ [name]) elemType defs).optionalValue
           )
           # Push down position info.
           (map (def: listToAttrs (mapAttrsToList (n: def':
             { name = n; value = { inherit (def) file; value = def'; }; }) def.value)) defs)));
-      getSubOptions = elemType.getSubOptions;
-      getSubOptionsPrefixed = prefix: elemType.getSubOptionsPrefixed (prefix ++ ["<name>"]);
+      getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]);
       getSubModules = elemType.getSubModules;
       substSubModules = m: attrsOf (elemType.substSubModules m);
-      nestedTypes = elemType.nestedTypes;
-      defaultValues = [{}];
     };
 
     # List or attribute set of ...
@@ -220,23 +159,18 @@ rec {
         attrOnly = attrsOf elemType;
       in mkOptionType {
         name = "list or attribute set of ${elemType.name}s";
-        typerep = "(loaOf${elemType.typerep})";
         check = x: isList x || isAttrs x;
-        merge = _module: loc: defs: attrOnly.merge _module loc (imap convertIfList defs);
-        getSubOptions = elemType.getSubOptions;
-        getSubOptionsPrefixed = prefix: elemType.getSubOptionsPrefixed (prefix ++ ["<name?>"]);
+        merge = loc: defs: attrOnly.merge loc (imap convertIfList defs);
+        getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]);
         getSubModules = elemType.getSubModules;
         substSubModules = m: loaOf (elemType.substSubModules m);
-        nestedTypes = elemType.nestedTypes;
-        defaultValues = [{} []];
       };
 
     # List or element of ...
     loeOf = elemType: mkOptionType {
       name = "element or list of ${elemType.name}s";
-      typerep = "(loeOf${elemType.typerep})";
       check = x: isList x || elemType.check x;
-      merge = _module: loc: defs:
+      merge = loc: defs:
         let
           defs' = filterOverrides defs;
           res = (head defs').value;
@@ -247,136 +181,81 @@ rec {
         else if !isString res then
           throw "The option `${showOption loc}' does not have a string value, in ${showFiles (getFiles defs)}."
         else res;
-      nestedTypes = elemType.nestedTypes;
-      defaultValues = [[]] ++ elemType.defaultValues;
     };
 
     uniq = elemType: mkOptionType {
-      inherit (elemType) check;
-      name = "unique ${elemType.name}";
-      typerep = "(uniq${elemType.typerep})";
+      inherit (elemType) name check;
       merge = mergeOneOption;
       getSubOptions = elemType.getSubOptions;
-      getSubOptionsPrefixed = prefix: elemType.getSubOptionsPrefixed prefix;
       getSubModules = elemType.getSubModules;
       substSubModules = m: uniq (elemType.substSubModules m);
-      nestedTypes = elemType.nestedTypes;
-      defaultValues = elemType.defaultValues;
     };
 
     nullOr = elemType: mkOptionType {
       name = "null or ${elemType.name}";
-      typerep = "(nullOr${elemType.typerep})";
       check = x: x == null || elemType.check x;
-      merge = _module: loc: defs:
+      merge = loc: defs:
         let nrNulls = count (def: def.value == null) defs; in
         if nrNulls == length defs then null
         else if nrNulls != 0 then
           throw "The option `${showOption loc}' is defined both null and not null, in ${showFiles (getFiles defs)}."
-        else elemType.merge _module loc defs;
+        else elemType.merge loc defs;
       getSubOptions = elemType.getSubOptions;
-      getSubOptionsPrefixed = prefix: elemType.getSubOptionsPrefixed prefix;
       getSubModules = elemType.getSubModules;
       substSubModules = m: nullOr (elemType.substSubModules m);
-      nestedTypes = elemType.nestedTypes;
-      defaultValues = [null] ++ elemType.defaultValues;
-    };
-
-    enum = values:
-      let
-        show = v:
-               if builtins.isString v then ''"${v}"''
-          else if builtins.isInt v then builtins.toString v
-          else ''<${builtins.typeOf v}>'';
-      in
-      mkOptionType {
-        name = "one of ${concatMapStringsSep ", " show values}";
-        typerep = "(enum${concatMapStrings (x: "(${escape ["(" ")"] (builtins.toString x)})") values})";
-        check = flip elem values;
-        merge = mergeOneOption;
-        nestedTypes = [];
-      };
-
-    either = t1: t2: mkOptionType {
-      name = "${t1.name} or ${t2.name}";
-      typerep = "(either${t1.typerep}${t2.typerep})";
-      check = x: t1.check x || t2.check x;
-      merge = mergeOneOption;
-      nestedTypes = t1.nestedTypes ++ t2.nestedTypes;
-      defaultValues = t1.defaultValues ++ t2.defaultValues;
     };
 
-
-    #
-    # Complex types
-    #
-
     submodule = opts:
       let
         opts' = toList opts;
         inherit (import ./modules.nix) evalModules;
-        filterVisible = filter (opt: (if opt ? visible then opt.visible else true) && (if opt ? internal then !opt.internal else true));
       in
       mkOptionType rec {
         name = "submodule";
-        typerep = "(submodule)";
         check = x: isAttrs x || isFunction x;
-        merge = _module: loc: defs:
+        merge = loc: defs:
           let
-            internalModule = [ { inherit _module; } { _module.args.name = lib.mkForce (last loc); } ];
             coerce = def: if isFunction def then def else { config = def; };
-            modules = opts' ++ internalModule ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs;
+            modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs;
           in (evalModules {
             inherit modules;
+            args.name = last loc;
             prefix = loc;
           }).config;
-        getSubOptions = getSubOptionsPrefixed [];
-        getSubOptionsPrefixed = prefix: _module:
-          let
+        getSubOptions = prefix: (evalModules
+          { modules = opts'; inherit prefix;
             # FIXME: hack to get shit to evaluate.
-            internalModule = [ { inherit _module; } { _module.args.name = lib.mkForce ""; } ];
-          in (evalModules {
-            modules = opts' ++ internalModule;
-            inherit prefix;
-          }).options;
+            args = { name = ""; }; }).options;
         getSubModules = opts';
         substSubModules = m: submodule m;
-        nestedTypes = concatMap (opt: opt.type.nestedTypes) (collect (lib.isType "option") (getSubOptions {}));
-        defaultValues = [{}];
       };
 
+    enum = values:
+      let
+        show = v:
+               if builtins.isString v then ''"${v}"''
+          else if builtins.isInt v then builtins.toString v
+          else ''<${builtins.typeOf v}>'';
+      in
+      mkOptionType {
+        name = "one of ${concatMapStringsSep ", " show values}";
+        check = flip elem values;
+        merge = mergeOneOption;
+      };
 
-
-    #
-    # Legacy types
-    #
+    either = t1: t2: mkOptionType {
+      name = "${t1.name} or ${t2.name}";
+      check = x: t1.check x || t2.check x;
+      merge = mergeOneOption;
+    };
 
     # Obsolete alternative to configOf.  It takes its option
     # declarations from the ‘options’ attribute of containing option
     # declaration.
     optionSet = mkOptionType {
       name = /* builtins.trace "types.optionSet is deprecated; use types.submodule instead" */ "option set";
-      typerep = "(optionSet)";
     };
 
-
-    # Try to remove module options of that type wherever possible.
-    # A module option taking a function can not be introspected and documented properly.
-    functionTo = resultType:
-      mkOptionType {
-        name = "function to ${resultType.name}";
-        typerep = "(function${resultType.typerep})";
-        check = builtins.isFunction;
-        merge = mergeOneOption;
-        nestedTypes = resultType.nestedTypes;
-        defaultValues = map (x: {...}:x) resultType.nestedTypes; # INFO: It seems as nix can't compare functions, yet.
-      };
-
-
-    #
-    # misc
-    #
-
     # Augment the given type with an additional type check function.
     addCheck = elemType: check: elemType // { check = x: elemType.check x && check x; };