!wfudwzqQUiJYJnqfSY:nixos.org

NixOS Module System

211 Members
51 Servers

Load older messages


SenderMessageTime
22 May 2026
@polykernel:kde.orgpolykernel I found where my error is. I need to override typeMerge as well since shallowing functor after the mkOptionType call won't affect the typeMerge field. 21:53:07
@polykernel:kde.orgpolykernel

Here is the updated working example in case it helps anyone in the future:

{
  pkgs ? import <nixpkgs> { },
  lib ? pkgs.lib,
}:

let
  testSubmodule =
    { config, ... }:
    {
      freeformType = lib.types.lazyAttrsOf lib.types.raw;

      options.a = lib.mkOption {
        type = lib.types.int;
        default = 0;
      };
    };

  isSubmoduleFn =
    m:
    let
      args = builtins.functionArgs m;
    in
    args ? lib || args ? config || args ? options;

  customSubmoduleWith =
    attrs:
    let
      t = lib.types.addCheck (lib.types.submoduleWith attrs) (v: builtins.isAttrs v || isSubmoduleFn v);
    in
    t
    // rec {
      substSubmodules = m: customSubmoduleWith (attrs // { modules = m; });
      functor = t.functor // {
        type = customSubmoduleWith;
      };
      typeMerge = lib.types.defaultTypeMerge functor;
    };

  customSubmodule =
    module:
    customSubmoduleWith {
      shorthandOnlyDefinesConfig = true;
      modules = [ module ];
    };

  staticInnerType = customSubmodule testSubmodule;

  dynamicInnerType = lib.types.functionTo staticInnerType;

  innerType = lib.types.either staticInnerType dynamicInnerType;

  testType = lib.types.lazyAttrsOf innerType;

  optionModule1 = {
    options.test = lib.mkOption {
      type = testType;
    };
  };

  optionModule2 = {
    options.test = lib.mkOption {
      type =
        let
          t = customSubmodule {
            options.b = lib.mkOption {
              type = lib.types.bool;
            };
          };
        in
        lib.types.lazyAttrsOf (lib.types.either t (lib.types.functionTo t));
    };
  };

  staticConfig = {
    config.test.random2 = {
      b = false;
    };
  };

  dynamicConfig = {
    config.test.random1 =
      { arg1 }:
      {
        a = 1;
      };
  };

  result = lib.evalModules {
    modules = [
      optionModule1
      optionModule2

      staticConfig
      dynamicConfig
    ];
  };
in
result
21:54:16
@hsjobeki:matrix.orghsjobekihttps://github.com/NixOS/nixpkgs/issues/396021 This limitation of addCheck is known. Fyi the more "idiomatic" way is to use mkOptionType to create a custom type such as it is done in lib/types.nix itself. 22:06:04
@polykernel:kde.orgpolykernelAh, for some reason I skipped over the link to that issue in the comment when reading. Thanks for the pointer.22:16:22
@polykernel:kde.orgpolykernelI haven't done a lot of thinking on this but is it possible to overcome this limitation by using some fixpoint mechanism like overlays? The problem seems to be that the type functor only has access to the type when it is defined (at the mkOptionType call site), not the type that is actually materalized (after all // updates). If the materialized type is accessible to the type functor, I think we can create a replica of the type.22:31:18
23 May 2026
@mattsturg:matrix.orgMatt Sturgeon

using some fixpoint mechanism like overlays?

Maybe mkOptionType could apply mkExtensible, which adds the .extend attribute? addCheck could then apply an overlay to <type>.extend 🤔

20:30:14
24 May 2026
@jwh4j4ez25q:matrix.orgmaurice joined the room.18:17:10
26 May 2026
@nam3l33ss:matrix.org·☽•Nameless☆•777 · ± changed their profile picture.05:42:37
@phanirithvij:matrix.orgloudgolem changed their display name from loudgolem to phanirithvij.11:41:58
27 May 2026
@isabel:isabelroses.comisabel changed their profile picture.21:17:16
28 May 2026
@define9293:matrix.orgdefine9293 joined the room.02:06:27
29 May 2026
@necoro:nixos.devNecoro joined the room.09:16:41
@louis2747:matrix.orgLouis2747 joined the room.09:52:55
@toonn:matrix.orgtoonn joined the room.10:16:32
@toonn:matrix.orgtoonn So I ran into a `nullOr submodule` option (pixelfed.nginx) and the only way I've found to get at its options is `(head (head (services.pixelfed.nginx.type.functor.payload 10:26:46
@toonn:matrix.orgtoonn .elemType.functor.payload.modules)).imports).options` 10:26:50
@toonn:matrix.orgtoonn Is there a better way? I've been avoiding getSubOptions because it claims to be for documentation. I started out using `optionAttrSetToDocList` but that was too focused on documentation, meaning I needed to parse descriptions to get integer bounds information and such. 10:28:59
@mattsturg:matrix.orgMatt SturgeonI've just opened https://github.com/NixOS/nixpkgs/pull/52551910:29:37
@mattsturg:matrix.orgMatt Sturgeon getSubOptions doesn't help you if you want access to the actual options' definitions, highestPrio, etc from the merged submodule. Because getSubOptions is intended for documentation purposes, it only merges modules from the type instantiation; modules from config definitions are not considered. 10:31:31
@mattsturg:matrix.orgMatt Sturgeon

E.g.

{
  options.foo = mkOption {
    type = submodule {
      # This module is in `getSubOptions` _and_ `valueMeta.configuration`
    };
  };
  config.foo = {
    # This module is only in `valueMeta.configuration`, not `getSubOptions`
  };
}
10:38:39
@mattsturg:matrix.orgMatt Sturgeon * I've just opened https://github.com/NixOS/nixpkgs/pull/525519 to address nullOr's v2 support, but there are other wrapper types we need to address too. 10:44:25
@mattsturg:matrix.orgMatt Sturgeon * toonn I've just opened https://github.com/NixOS/nixpkgs/pull/525519 to address nullOr's v2 support, but there are other wrapper types we need to address too. 10:44:48
@winston:winston.shwinston joined the room.11:06:10
@toonn:matrix.orgtoonn I am only interested in the definition of options though. I don't care what options someone specifies as part of an open submodule. Though I am interested in any freeformType restricting such extra options. 11:21:15
@toonn:matrix.orgtoonn So without nullOr's v2 support I am in fact stuck digging in the functor.payload, right? 11:21:58
@mattsturg:matrix.orgMatt Sturgeon

I feel like there's a subtle confusion going on here with what we mean by "definition".

A submodule is just another configuration, within a wider configuration, evaluated mostly in isolation.

Both the outer and sub configurations have modules, and those modules can contain config definitions for their respective configurations.

When I say valueMeta.configuration considers modules from config definitions, I mean config definitions in the outer configuration; definitions that define modules for the submodule to evaluate.

11:24:55
@mattsturg:matrix.orgMatt Sturgeon *

I feel like there's a subtle confusion going on here with what we mean by "definition".

A submodule is just another configuration, within a wider configuration, evaluated mostly in isolation.

The submodule type merges to its configuration's config value, and the configuration as a whole is exposed through valueMeta, which comes from v2 check+merge.

Both the outer and sub configurations have modules, and those modules can contain config definitions for their respective configurations.

When I say valueMeta considers modules from config definitions, I mean config definitions in the outer configuration; definitions that define modules for the submodule to evaluate.

11:27:52
@mattsturg:matrix.orgMatt Sturgeon

To oversimplify, a submodule-type's lifecycle is:

  1. the type is instantiated, with initial modules
    • options declared and defaults defined are visible to type.getSubOptions
  2. an option is declared (in a host configuration) using the type
  3. the option is defined (either via config or default, in the host configuration)
    • these definitions are modules
  4. the option is merged, using the type's merge function
    1. it extends its base configuration with the defined modules
    2. it exposes the final configuration via valueMeta = { inherit configuration; }
    3. it evaluates the final value as configuration.config
11:34:29
@toonn:matrix.orgtoonn OK, so when I say definition, I mean the options defined in <nixpkgs/nixos/modules>. 11:36:49
@toonn:matrix.orgtoonn I am trying to derive possible options and their types for NixOS modules. 11:37:40

Show newer messages


Back to Room ListRoom Version: 10