diff --git a/lib/options.nix b/lib/options.nix index f4d0d9d36cfc930..cf46e05b84706ee 100644 --- a/lib/options.nix +++ b/lib/options.nix @@ -438,7 +438,12 @@ rec { "*" # listOf (submodule {}) "" # functionTo ]; - in if builtins.elem part specialIdentifiers + # If the part is a named placeholder of the form "<...>" don't escape it. + # Required for compatibility with: namedAttrsOf + # Can lead to wrong escaping if somebody uses literally "<...>" in their option names. + # This is the trade-off to allow for named placeholders in option names. + isNamedPlaceholder = builtins.match "\<(.*)\>" part != null; + in if builtins.elem part specialIdentifiers || isNamedPlaceholder then part else lib.strings.escapeNixIdentifier part; in (concatStringsSep ".") (map escapeOptionPart parts); diff --git a/lib/types.nix b/lib/types.nix index 1fe1616c9cef57b..8d066ebd10c8571 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -626,7 +626,7 @@ rec { # Push down position info. (map (def: mapAttrs (n: v: { inherit (def) file; value = v; }) def.value) defs))); emptyValue = { value = {}; }; - getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<${attrName}>"]); + getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["{${attrName}}"]); getSubModules = elemType.getSubModules; substSubModules = m: namedAttrsOf attrName (elemType.substSubModules m); functor = (defaultFunctor name) // { wrapped = elemType; };