diff options
author | John Ericson <git@JohnEricson.me> | 2019-09-02 01:31:31 -0400 |
---|---|---|
committer | John Ericson <git@JohnEricson.me> | 2019-09-02 01:31:31 -0400 |
commit | c33d80c071927d783bd10943e723ed408ec89e48 (patch) | |
tree | ee0d82edaae37f797995468b8dbd5ce4beffab27 /lib | |
parent | 446f8c851d599326373a2c910841d092ff8e68ae (diff) | |
parent | 74b42e28b94cc42f93b50c5aeee8794f66795fd0 (diff) |
Merge remote-tracking branch 'upstream/master' into feature/js-unknown-ghcjs
Diffstat (limited to 'lib')
-rw-r--r-- | lib/default.nix | 10 | ||||
-rw-r--r-- | lib/fixed-points.nix | 9 | ||||
-rw-r--r-- | lib/generators.nix | 2 | ||||
-rw-r--r-- | lib/licenses.nix | 21 | ||||
-rw-r--r-- | lib/lists.nix | 18 | ||||
-rw-r--r-- | lib/modules.nix | 50 | ||||
-rw-r--r-- | lib/options.nix | 8 | ||||
-rw-r--r-- | lib/sources.nix | 24 | ||||
-rw-r--r-- | lib/strings.nix | 2 | ||||
-rw-r--r-- | lib/systems/default.nix | 31 | ||||
-rw-r--r-- | lib/systems/doubles.nix | 18 | ||||
-rw-r--r-- | lib/systems/examples.nix | 49 | ||||
-rw-r--r-- | lib/systems/for-meta.nix | 37 | ||||
-rw-r--r-- | lib/systems/inspect.nix | 4 | ||||
-rw-r--r-- | lib/systems/parse.nix | 123 | ||||
-rw-r--r-- | lib/systems/platforms.nix | 11 | ||||
-rwxr-xr-x | lib/tests/modules.sh | 11 | ||||
-rw-r--r-- | lib/tests/modules/alias-with-priority-can-override.nix | 9 | ||||
-rw-r--r-- | lib/tests/modules/alias-with-priority.nix | 5 | ||||
-rw-r--r-- | lib/tests/modules/declare-either.nix | 5 | ||||
-rw-r--r-- | lib/tests/modules/declare-oneOf.nix | 9 | ||||
-rw-r--r-- | lib/tests/release.nix | 15 | ||||
-rw-r--r-- | lib/tests/systems.nix | 12 | ||||
-rw-r--r-- | lib/trivial.nix | 7 | ||||
-rw-r--r-- | lib/types.nix | 26 |
25 files changed, 339 insertions, 177 deletions
diff --git a/lib/default.nix b/lib/default.nix index d400907ebb0cb..18d2dfae1e183 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -50,7 +50,7 @@ let filesystem = callLibs ./filesystem.nix; # back-compat aliases - platforms = systems.forMeta; + platforms = systems.doubles; inherit (builtins) add addErrorContext attrNames concatLists deepSeq elem elemAt filter genericClosure genList getAttr @@ -59,7 +59,7 @@ let stringLength sub substring tail; inherit (trivial) id const concat or and bitAnd bitOr bitXor bitNot boolToString mergeAttrs flip mapNullable inNixShell min max - importJSON warn info nixpkgsVersion version mod compare + importJSON warn info showWarnings nixpkgsVersion version mod compare splitByAndCompare functionArgs setFunctionArgs isFunction; inherit (fixedPoints) fix fix' converge extends composeExtensions makeExtensible makeExtensibleWithCustomName; @@ -71,7 +71,7 @@ let zipAttrsWithNames zipAttrsWith zipAttrs recursiveUpdateUntil recursiveUpdate matchAttrs overrideExisting getOutput getBin getLib getDev chooseDevOutputs zipWithNames zip; - inherit (lists) singleton foldr fold foldl foldl' imap0 imap1 + inherit (lists) singleton forEach foldr fold foldl foldl' imap0 imap1 concatMap flatten remove findSingle findFirst any all count optional optionals toList range partition zipListsWith zipLists reverseList listDfs toposort sort naturalSort compareLists take @@ -81,7 +81,7 @@ let intersperse concatStringsSep concatMapStringsSep concatImapStringsSep makeSearchPath makeSearchPathOutput makeLibraryPath makeBinPath optionalString - hasPrefix hasSuffix stringToCharacters stringAsChars escape + hasInfix hasPrefix hasSuffix stringToCharacters stringAsChars escape escapeShellArg escapeShellArgs replaceChars lowerChars upperChars toLower toUpper addContextFrom splitString removePrefix removeSuffix versionOlder versionAtLeast getVersion @@ -109,7 +109,7 @@ let mkFixStrictness mkOrder mkBefore mkAfter mkAliasDefinitions mkAliasAndWrapDefinitions fixMergeModules mkRemovedOptionModule mkRenamedOptionModule mkMergedOptionModule mkChangedOptionModule - mkAliasOptionModule mkAliasOptionModuleWithPriority doRename filterModules; + mkAliasOptionModule doRename filterModules; inherit (options) isOption mkEnableOption mkSinkUndeclaredOptions mergeDefaultOption mergeOneOption mergeEqualOption getValues getFiles optionAttrSetToDocList optionAttrSetToDocList' diff --git a/lib/fixed-points.nix b/lib/fixed-points.nix index 2f818c88de5db..968930526a639 100644 --- a/lib/fixed-points.nix +++ b/lib/fixed-points.nix @@ -30,9 +30,12 @@ rec { # nix-repl> converge (x: x / 2) 16 # 0 converge = f: x: - if (f x) == x - then x - else converge f (f x); + let + x' = f x; + in + if x' == x + then x + else converge f x'; # Modify the contents of an explicitly recursive attribute set in a way that # honors `self`-references. This is accomplished with a function diff --git a/lib/generators.nix b/lib/generators.nix index 863ba847423ee..a71654bec6c36 100644 --- a/lib/generators.nix +++ b/lib/generators.nix @@ -178,7 +178,7 @@ rec { toPlist = {}: v: let isFloat = builtins.isFloat or (x: false); expr = ind: x: with builtins; - if isNull x then "" else + if x == null then "" else if isBool x then bool ind x else if isInt x then int ind x else if isString x then str ind x else diff --git a/lib/licenses.nix b/lib/licenses.nix index b022d8bc11bf6..c964060d2a5c8 100644 --- a/lib/licenses.nix +++ b/lib/licenses.nix @@ -145,6 +145,12 @@ lib.mapAttrs (n: v: v // { shortName = n; }) rec { free = false; }; + cc-by-nc-30 = spdx { + spdxId = "CC-BY-NC-3.0"; + fullName = "Creative Commons Attribution Non Commercial 3.0 Unported"; + free = false; + }; + cc-by-nc-40 = spdx { spdxId = "CC-BY-NC-4.0"; fullName = "Creative Commons Attribution Non Commercial 4.0 International"; @@ -428,12 +434,12 @@ lib.mapAttrs (n: v: v // { shortName = n; }) rec { lgpl21 = spdx { spdxId = "LGPL-2.1-only"; - fullName = "GNU Library General Public License v2.1 only"; + fullName = "GNU Lesser General Public License v2.1 only"; }; lgpl21Plus = spdx { spdxId = "LGPL-2.1-or-later"; - fullName = "GNU Library General Public License v2.1 or later"; + fullName = "GNU Lesser General Public License v2.1 or later"; }; lgpl3 = spdx { @@ -451,9 +457,9 @@ lib.mapAttrs (n: v: v // { shortName = n; }) rec { fullName = "libpng License"; }; - libpng2 = { - fullName = "libpng License v2"; # 1.6.36+ - url = "http://www.libpng.org/pub/png/src/libpng-LICENSE.txt"; + libpng2 = spdx { + spdxId = "libpng-2.0"; # Used since libpng 1.6.36. + fullName = "PNG Reference Library version 2"; }; libtiff = spdx { @@ -561,6 +567,11 @@ lib.mapAttrs (n: v: v // { shortName = n; }) rec { fullName = "OpenSSL License"; }; + osl2 = spdx { + spdxId = "OSL-2.0"; + fullName = "Open Software License 2.0"; + }; + osl21 = spdx { spdxId = "OSL-2.1"; fullName = "Open Software License 2.1"; diff --git a/lib/lists.nix b/lib/lists.nix index be541427c2470..e4fcf959b60c8 100644 --- a/lib/lists.nix +++ b/lib/lists.nix @@ -7,7 +7,7 @@ let in rec { - inherit (builtins) head tail length isList elemAt concatLists filter elem genList; + inherit (builtins) head tail length isList elemAt concatLists filter elem genList map; /* Create a list consisting of a single element. `singleton x` is sometimes more convenient with respect to indentation than `[x]` @@ -21,6 +21,19 @@ rec { */ singleton = x: [x]; + /* Apply the function to each element in the list. Same as `map`, but arguments + flipped. + + Type: forEach :: [a] -> (a -> b) -> [b] + + Example: + forEach [ 1 2 ] (x: + toString x + ) + => [ "1" "2" ] + */ + forEach = xs: f: map f xs; + /* “right fold” a binary function `op` between successive elements of `list` with `nul' as the starting value, i.e., `foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))`. @@ -633,8 +646,7 @@ rec { else let x = head list; - xs = unique (drop 1 list); - in [x] ++ remove x xs; + in [x] ++ unique (remove x list); /* Intersects list 'e' and another list. O(nm) complexity. diff --git a/lib/modules.nix b/lib/modules.nix index 5c9d66d8f97b9..c3c903c1dfa80 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -323,16 +323,14 @@ rec { else 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 - # value computed from the definitions. - value = - if !res.isDefined then - throw "The option `${showOption loc}' is used but not defined." - else if opt ? apply then - opt.apply res.mergedValue - else - res.mergedValue; + + # The value with a check that it is defined + valueDefined = if res.isDefined then res.mergedValue else + throw "The option `${showOption loc}' is used but not defined."; + + # Apply the 'apply' function to the merged value. This allows options to + # yield a value computed from the definitions + value = if opt ? apply then opt.apply valueDefined else valueDefined; in opt // { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value; @@ -476,8 +474,22 @@ rec { optionSet to options of type submodule. FIXME: remove eventually. */ fixupOptionType = loc: opt: - if opt.type.getSubModules or null == null - then opt // { type = opt.type or types.unspecified; } + let + options = opt.options or + (throw "Option `${showOption loc'}' has type optionSet but has no option attribute, in ${showFiles opt.declarations}."); + f = tp: + let optionSetIn = type: (tp.name == type) && (tp.functor.wrapped.name == "optionSet"); + in + if tp.name == "option set" || tp.name == "submodule" then + throw "The option ${showOption loc} uses submodules without a wrapping type, in ${showFiles opt.declarations}." + else if optionSetIn "attrsOf" then types.attrsOf (types.submodule options) + else if optionSetIn "loaOf" then types.loaOf (types.submodule options) + else if optionSetIn "listOf" then types.listOf (types.submodule options) + else if optionSetIn "nullOr" then types.nullOr (types.submodule options) + else tp; + in + if opt.type.getSubModules or null == null + then opt // { type = f (opt.type or types.unspecified); } else opt // { type = opt.type.substSubModules opt.options; options = []; }; @@ -596,6 +608,9 @@ rec { forwards any definitions of boot.copyKernels to boot.loader.grub.copyKernels while printing a warning. + + This also copies over the priority from the aliased option to the + non-aliased option. */ mkRenamedOptionModule = from: to: doRename { inherit from to; @@ -690,16 +705,7 @@ rec { use = id; }; - /* Like ‘mkAliasOptionModule’, but copy over the priority of the option as well. */ - mkAliasOptionModuleWithPriority = from: to: doRename { - inherit from to; - visible = true; - warn = false; - use = id; - withPriority = true; - }; - - doRename = { from, to, visible, warn, use, withPriority ? false }: + doRename = { from, to, visible, warn, use, withPriority ? true }: { config, options, ... }: let fromOpt = getAttrFromPath from options; diff --git a/lib/options.nix b/lib/options.nix index 5cea99067aaba..e5c0631a54373 100644 --- a/lib/options.nix +++ b/lib/options.nix @@ -36,7 +36,7 @@ rec { example ? null, # String describing the option. description ? null, - # Related packages used in the manual (see `genRelatedPackages` in ../nixos/doc/manual/default.nix). + # Related packages used in the manual (see `genRelatedPackages` in ../nixos/lib/make-options-doc/default.nix). relatedPackages ? null, # Option type, providing type-checking and value merging. type ? null, @@ -48,6 +48,8 @@ rec { visible ? null, # Whether the option can be set only once readOnly ? null, + # Deprecated, used by types.optionSet. + options ? null } @ attrs: attrs // { _type = "option"; }; @@ -99,7 +101,7 @@ rec { 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)}." + throw "The unique option `${showOption loc}' is defined multiple times, in:\n - ${concatStringsSep "\n - " (getFiles defs)}." else (head defs).value; /* "Merge" option definitions by checking that they all have the same value. */ @@ -141,7 +143,7 @@ rec { docOption = rec { loc = opt.loc; name = showOption opt.loc; - description = opt.description or (throw "Option `${name}' has no description."); + description = opt.description or (lib.warn "Option `${name}' has no description." "This option has no description."); declarations = filter (x: x != unknownModule) opt.declarations; internal = opt.internal or false; visible = opt.visible or true; diff --git a/lib/sources.nix b/lib/sources.nix index 1a9f3f7d1f343..c4680087b2454 100644 --- a/lib/sources.nix +++ b/lib/sources.nix @@ -12,8 +12,8 @@ rec { # Bring in a path as a source, filtering out all Subversion and CVS # directories, as well as backup files (*~). cleanSourceFilter = name: type: let baseName = baseNameOf (toString name); in ! ( - # Filter out Subversion and CVS directories. - (type == "directory" && (baseName == ".git" || baseName == ".svn" || baseName == "CVS" || baseName == ".hg")) || + # Filter out version control software files/directories + (baseName == ".git" || type == "directory" && (baseName == ".svn" || baseName == "CVS" || baseName == ".hg")) || # Filter out editor backup / swap files. lib.hasSuffix "~" baseName || builtins.match "^\\.sw[a-z]$" baseName != null || @@ -53,12 +53,16 @@ rec { # Filter sources by a list of regular expressions. # # E.g. `src = sourceByRegex ./my-subproject [".*\.py$" "^database.sql$"]` - sourceByRegex = src: regexes: cleanSourceWith { - filter = (path: type: - let relPath = lib.removePrefix (toString src + "/") (toString path); - in lib.any (re: builtins.match re relPath != null) regexes); - inherit src; - }; + sourceByRegex = src: regexes: + let + isFiltered = src ? _isLibCleanSourceWith; + origSrc = if isFiltered then src.origSrc else src; + in lib.cleanSourceWith { + filter = (path: type: + let relPath = lib.removePrefix (toString origSrc + "/") (toString path); + in lib.any (re: builtins.match re relPath != null) regexes); + inherit src; + }; # Get all files ending with the specified suffices from the given # directory or its descendants. E.g. `sourceFilesBySuffices ./dir @@ -83,7 +87,7 @@ rec { # Sometimes git stores the commitId directly in the file but # sometimes it stores something like: «ref: refs/heads/branch-name» matchRef = match "^ref: (.*)$" fileContent; - in if isNull matchRef + in if matchRef == null then fileContent else readCommitFromFile (lib.head matchRef) path # Sometimes, the file isn't there at all and has been packed away in the @@ -92,7 +96,7 @@ rec { then let fileContent = readFile packedRefsName; matchRef = match (".*\n([^\n ]*) " + file + "\n.*") fileContent; - in if isNull matchRef + in if matchRef == null then throw ("Could not find " + file + " in " + packedRefsName) else lib.head matchRef else throw ("Not a .git directory: " + path); diff --git a/lib/strings.nix b/lib/strings.nix index 47c881cfbc7cc..ae0d74c6721dc 100644 --- a/lib/strings.nix +++ b/lib/strings.nix @@ -90,7 +90,7 @@ rec { /* Same as `concatMapStringsSep`, but the mapping function additionally receives the position of its argument. - Type: concatMapStringsSep :: string -> (int -> string -> string) -> [string] -> string + Type: concatIMapStringsSep :: string -> (int -> string -> string) -> [string] -> string Example: concatImapStringsSep "-" (pos: x: toString (x / pos)) [ 6 6 6 ] diff --git a/lib/systems/default.nix b/lib/systems/default.nix index 77f200952958b..8aa413f53817b 100644 --- a/lib/systems/default.nix +++ b/lib/systems/default.nix @@ -3,7 +3,6 @@ rec { doubles = import ./doubles.nix { inherit lib; }; - forMeta = import ./for-meta.nix { inherit lib; }; parse = import ./parse.nix { inherit lib; }; inspect = import ./inspect.nix { inherit lib; }; platforms = import ./platforms.nix { inherit lib; }; @@ -15,7 +14,9 @@ rec { # `parsed` is inferred from args, both because there are two options with one # clearly prefered, and to prevent cycles. A simpler fixed point where the RHS # always just used `final.*` would fail on both counts. - elaborate = args: let + elaborate = args': let + args = if lib.isString args' then { system = args'; } + else args'; final = { # Prefer to parse `config` as it is strictly more informative. parsed = parse.mkSystemFromString (if args ? config then args.config else args.system); @@ -24,15 +25,20 @@ rec { config = parse.tripleFromSystem final.parsed; # Just a guess, based on `system` platform = platforms.selectBySystem final.system; + # Determine whether we are compatible with the provided CPU + isCompatible = platform: parse.isCompatible final.parsed.cpu platform.parsed.cpu; # Derived meta-data libc = /**/ if final.isDarwin then "libSystem" else if final.isMinGW then "msvcrt" + else if final.isWasi then "wasilibc" else if final.isMusl then "musl" else if final.isUClibc then "uclibc" else if final.isAndroid then "bionic" else if final.isLinux /* default */ then "glibc" + else if final.isMsp430 then "newlib" else if final.isAvr then "avrlibc" + else if final.isNetBSD then "nblibc" # TODO(@Ericson2314) think more about other operating systems else "native/impure"; extensions = { @@ -58,7 +64,7 @@ rec { "netbsd" = "NetBSD"; "freebsd" = "FreeBSD"; "openbsd" = "OpenBSD"; - "wasm" = "Wasm"; + "wasi" = "Wasi"; }.${final.parsed.kernel.name} or null; # uname -p @@ -68,16 +74,22 @@ rec { release = null; }; + kernelArch = + if final.isAarch32 then "arm" + else if final.isAarch64 then "arm64" + else if final.isx86_32 then "x86" + else if final.isx86_64 then "ia64" + else final.parsed.cpu.name; + qemuArch = if final.isArm then "arm" else if final.isx86_64 then "x86_64" else if final.isx86 then "i386" else { "powerpc" = "ppc"; + "powerpcle" = "ppc"; "powerpc64" = "ppc64"; - "powerpc64le" = "ppc64"; - "mips64" = "mips"; - "mipsel64" = "mipsel"; + "powerpc64le" = "ppc64le"; }.${final.parsed.cpu.name} or final.parsed.cpu.name; emulator = pkgs: let @@ -98,13 +110,14 @@ rec { wine = (pkgs.winePackagesFor wine-name).minimal; in if final.parsed.kernel.name == pkgs.stdenv.hostPlatform.parsed.kernel.name && - (final.parsed.cpu.name == pkgs.stdenv.hostPlatform.parsed.cpu.name || - (final.isi686 && pkgs.stdenv.hostPlatform.isx86_64)) - then pkgs.runtimeShell + pkgs.stdenv.hostPlatform.isCompatible final + then "${pkgs.runtimeShell} -c '\"$@\"' --" else if final.isWindows then "${wine}/bin/${wine-name}" else if final.isLinux && pkgs.stdenv.hostPlatform.isLinux then "${qemu-user}/bin/qemu-${final.qemuArch}" + else if final.isWasi + then "${pkgs.wasmtime}/bin/wasmtime" else throw "Don't know how to run ${final.config} executables."; } // mapAttrs (n: v: v final.parsed) inspect.predicates diff --git a/lib/systems/doubles.nix b/lib/systems/doubles.nix index 58677c0bdd900..823f6a915d6e7 100644 --- a/lib/systems/doubles.nix +++ b/lib/systems/doubles.nix @@ -13,10 +13,20 @@ let "i686-cygwin" "i686-freebsd" "i686-linux" "i686-netbsd" "i686-openbsd" - "x86_64-cygwin" "x86_64-darwin" "x86_64-freebsd" "x86_64-linux" + "x86_64-cygwin" "x86_64-freebsd" "x86_64-linux" "x86_64-netbsd" "x86_64-openbsd" "x86_64-solaris" + "x86_64-darwin" "i686-darwin" "aarch64-darwin" "armv7a-darwin" + "x86_64-windows" "i686-windows" + + "wasm64-wasi" "wasm32-wasi" + + "powerpc64le-linux" + + "riscv32-linux" "riscv64-linux" + + "aarch64-none" "avr-none" "arm-none" "i686-none" "x86_64-none" "powerpc-none" "msp430-none" "riscv64-none" "riscv32-none" ]; allParsed = map parse.mkSystemFromString all; @@ -34,6 +44,7 @@ in rec { i686 = filterDoubles predicates.isi686; x86_64 = filterDoubles predicates.isx86_64; mips = filterDoubles predicates.isMips; + riscv = filterDoubles predicates.isRiscV; cygwin = filterDoubles predicates.isCygwin; darwin = filterDoubles predicates.isDarwin; @@ -45,7 +56,10 @@ in rec { netbsd = filterDoubles predicates.isNetBSD; openbsd = filterDoubles predicates.isOpenBSD; unix = filterDoubles predicates.isUnix; + wasi = filterDoubles predicates.isWasi; windows = filterDoubles predicates.isWindows; - mesaPlatforms = ["i686-linux" "x86_64-linux" "x86_64-darwin" "armv5tel-linux" "armv6l-linux" "armv7l-linux" "aarch64-linux" "powerpc64le-linux"]; + embedded = filterDoubles predicates.isNone; + + mesaPlatforms = ["i686-linux" "x86_64-linux" "x86_64-darwin" "armv5tel-linux" "armv6l-linux" "armv7l-linux" "armv7a-linux" "aarch64-linux" "powerpc64le-linux"]; } diff --git a/lib/systems/examples.nix b/lib/systems/examples.nix index 90068f566ed08..4861fe634a02e 100644 --- a/lib/systems/examples.nix +++ b/lib/systems/examples.nix @@ -44,14 +44,6 @@ rec { platform = platforms.aarch64-multiplatform; }; - armv5te-android-prebuilt = rec { - config = "armv5tel-unknown-linux-androideabi"; - sdkVer = "21"; - ndkVer = "18b"; - platform = platforms.armv5te-android; - useAndroidPrebuilt = true; - }; - armv7a-android-prebuilt = rec { config = "armv7a-unknown-linux-androideabi"; sdkVer = "24"; @@ -96,12 +88,32 @@ rec { config = "aarch64-unknown-linux-musl"; }; + gnu64 = { config = "x86_64-unknown-linux-gnu"; }; + gnu32 = { config = "i686-unknown-linux-gnu"; }; + musl64 = { config = "x86_64-unknown-linux-musl"; }; musl32 = { config = "i686-unknown-linux-musl"; }; riscv64 = riscv "64"; riscv32 = riscv "32"; + riscv64-embedded = { + config = "riscv64-none-elf"; + libc = "newlib"; + platform = platforms.riscv-multiplatform "64"; + }; + + riscv32-embedded = { + config = "riscv32-none-elf"; + libc = "newlib"; + platform = platforms.riscv-multiplatform "32"; + }; + + msp430 = { + config = "msp430-elf"; + libc = "newlib"; + }; + avr = { config = "avr"; }; @@ -135,11 +147,6 @@ rec { libc = "newlib"; }; - alpha-embedded = { - config = "alpha-elf"; - libc = "newlib"; - }; - i686-embedded = { config = "i686-elf"; libc = "newlib"; @@ -213,6 +220,22 @@ rec { platform = {}; }; + # BSDs + + amd64-netbsd = { + config = "x86_64-unknown-netbsd"; + libc = "nblibc"; + }; + + # + # WASM + # + + wasi32 = { + config = "wasm32-unknown-wasi"; + useLLVM = true; + }; + # Ghcjs ghcjs = { config = "js-unknown-ghcjs"; diff --git a/lib/systems/for-meta.nix b/lib/systems/for-meta.nix deleted file mode 100644 index 51fb6ae760d1e..0000000000000 --- a/lib/systems/for-meta.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ lib }: -let - inherit (lib.systems) parse; - inherit (lib.systems.inspect) patterns; - - abis = lib.mapAttrs (_: abi: builtins.removeAttrs abi [ "assertions" ]) parse.abis; - -in rec { - all = [ {} ]; # `{}` matches anything - none = []; - - arm = [ patterns.isAarch32 ]; - aarch64 = [ patterns.isAarch64 ]; - x86 = [ patterns.isx86 ]; - i686 = [ patterns.isi686 ]; - x86_64 = [ patterns.isx86_64 ]; - mips = [ patterns.isMips ]; - riscv = [ patterns.isRiscV ]; - - cygwin = [ patterns.isCygwin ]; - darwin = [ patterns.isDarwin ]; - freebsd = [ patterns.isFreeBSD ]; - # Should be better, but MinGW is unclear. - gnu = [ - { kernel = parse.kernels.linux; abi = abis.gnu; } - { kernel = parse.kernels.linux; abi = abis.gnueabi; } - { kernel = parse.kernels.linux; abi = abis.gnueabihf; } - ]; - illumos = [ patterns.isSunOS ]; - linux = [ patterns.isLinux ]; - netbsd = [ patterns.isNetBSD ]; - openbsd = [ patterns.isOpenBSD ]; - unix = patterns.isUnix; # Actually a list - windows = [ patterns.isWindows ]; - - inherit (lib.systems.doubles) mesaPlatforms; -} diff --git a/lib/systems/inspect.nix b/lib/systems/inspect.nix index bf186126d4a9b..8a95787110b82 100644 --- a/lib/systems/inspect.nix +++ b/lib/systems/inspect.nix @@ -20,7 +20,9 @@ rec { isRiscV = { cpu = { family = "riscv"; }; }; isSparc = { cpu = { family = "sparc"; }; }; isWasm = { cpu = { family = "wasm"; }; }; + isMsp430 = { cpu = { family = "msp430"; }; }; isAvr = { cpu = { family = "avr"; }; }; + isAlpha = { cpu = { family = "alpha"; }; }; is32bit = { cpu = { bits = 32; }; }; is64bit = { cpu = { bits = 64; }; }; @@ -41,6 +43,8 @@ rec { isWindows = { kernel = kernels.windows; }; isCygwin = { kernel = kernels.windows; abi = abis.cygnus; }; isMinGW = { kernel = kernels.windows; abi = abis.gnu; }; + isWasi = { kernel = kernels.wasi; }; + isNone = { kernel = kernels.none; }; isAndroid = [ { abi = abis.android; } { abi = abis.androideabi; } ]; isMusl = with abis; map (a: { abi = a; }) [ musl musleabi musleabihf ]; diff --git a/lib/systems/parse.nix b/lib/systems/parse.nix index a20b334311efa..0c42689a9b137 100644 --- a/lib/systems/parse.nix +++ b/lib/systems/parse.nix @@ -69,24 +69,24 @@ rec { cpuTypes = with significantBytes; setTypes types.openCpuType { arm = { bits = 32; significantByte = littleEndian; family = "arm"; }; - armv5tel = { bits = 32; significantByte = littleEndian; family = "arm"; version = "5"; }; - armv6m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "6"; }; - armv6l = { bits = 32; significantByte = littleEndian; family = "arm"; version = "6"; }; - armv7a = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; }; - armv7r = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; }; - armv7m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; }; - armv7l = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; }; - armv8a = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; }; - armv8r = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; }; - armv8m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; }; - aarch64 = { bits = 64; significantByte = littleEndian; family = "arm"; version = "8"; }; - aarch64_be = { bits = 64; significantByte = bigEndian; family = "arm"; version = "8"; }; - - i386 = { bits = 32; significantByte = littleEndian; family = "x86"; }; - i486 = { bits = 32; significantByte = littleEndian; family = "x86"; }; - i586 = { bits = 32; significantByte = littleEndian; family = "x86"; }; - i686 = { bits = 32; significantByte = littleEndian; family = "x86"; }; - x86_64 = { bits = 64; significantByte = littleEndian; family = "x86"; }; + armv5tel = { bits = 32; significantByte = littleEndian; family = "arm"; version = "5"; arch = "armv5t"; }; + armv6m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "6"; arch = "armv6-m"; }; + armv6l = { bits = 32; significantByte = littleEndian; family = "arm"; version = "6"; arch = "armv6"; }; + armv7a = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; arch = "armv7-a"; }; + armv7r = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; arch = "armv7-r"; }; + armv7m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; arch = "armv7-m"; }; + armv7l = { bits = 32; significantByte = littleEndian; family = "arm"; version = "7"; arch = "armv7"; }; + armv8a = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; arch = "armv8-a"; }; + armv8r = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; arch = "armv8-a"; }; + armv8m = { bits = 32; significantByte = littleEndian; family = "arm"; version = "8"; arch = "armv8-m"; }; + aarch64 = { bits = 64; significantByte = littleEndian; family = "arm"; version = "8"; arch = "armv8-a"; }; + aarch64_be = { bits = 64; significantByte = bigEndian; family = "arm"; version = "8"; arch = "armv8-a"; }; + + i386 = { bits = 32; significantByte = littleEndian; family = "x86"; arch = "i386"; }; + i486 = { bits = 32; significantByte = littleEndian; family = "x86"; arch = "i486"; }; + i586 = { bits = 32; significantByte = littleEndian; family = "x86"; arch = "i586"; }; + i686 = { bits = 32; significantByte = littleEndian; family = "x86"; arch = "i686"; }; + x86_64 = { bits = 64; significantByte = littleEndian; family = "x86"; arch = "x86-64"; }; mips = { bits = 32; significantByte = bigEndian; family = "mips"; }; mipsel = { bits = 32; significantByte = littleEndian; family = "mips"; }; @@ -109,11 +109,92 @@ rec { alpha = { bits = 64; significantByte = littleEndian; family = "alpha"; }; + msp430 = { bits = 16; significantByte = littleEndian; family = "msp430"; }; avr = { bits = 8; family = "avr"; }; js = { bits = 32; significantByte = littleEndian; family = "js"; }; }; + # Determine where two CPUs are compatible with each other. That is, + # can we run code built for system b on system a? For that to + # happen, then the set of all possible possible programs that system + # b accepts must be a subset of the set of all programs that system + # a accepts. This compatibility relation forms a category where each + # CPU is an object and each arrow from a to b represents + # compatibility. CPUs with multiple modes of Endianness are + # isomorphic while all CPUs are endomorphic because any program + # built for a CPU can run on that CPU. + isCompatible = a: b: with cpuTypes; lib.any lib.id [ + # x86 + (b == i386 && isCompatible a i486) + (b == i486 && isCompatible a i586) + (b == i586 && isCompatible a i686) + + # XXX: Not true in some cases. Like in WSL mode. + (b == i686 && isCompatible a x86_64) + + # ARMv4 + (b == arm && isCompatible a armv5tel) + + # ARMv5 + (b == armv5tel && isCompatible a armv6l) + + # ARMv6 + (b == armv6l && isCompatible a armv6m) + (b == armv6m && isCompatible a armv7l) + + # ARMv7 + (b == armv7l && isCompatible a armv7a) + (b == armv7l && isCompatible a armv7r) + (b == armv7l && isCompatible a armv7m) + (b == armv7a && isCompatible a armv8a) + (b == armv7r && isCompatible a armv8a) + (b == armv7m && isCompatible a armv8a) + (b == armv7a && isCompatible a armv8r) + (b == armv7r && isCompatible a armv8r) + (b == armv7m && isCompatible a armv8r) + (b == armv7a && isCompatible a armv8m) + (b == armv7r && isCompatible a armv8m) + (b == armv7m && isCompatible a armv8m) + + # ARMv8 + (b == armv8r && isCompatible a armv8a) + (b == armv8m && isCompatible a armv8a) + + # XXX: not always true! Some arm64 cpus don’t support arm32 mode. + (b == aarch64 && a == armv8a) + (b == armv8a && isCompatible a aarch64) + + (b == aarch64 && a == aarch64_be) + (b == aarch64_be && isCompatible a aarch64) + + # PowerPC + (b == powerpc && isCompatible a powerpc64) + (b == powerpcle && isCompatible a powerpc) + (b == powerpc && a == powerpcle) + (b == powerpc64le && isCompatible a powerpc64) + (b == powerpc64 && a == powerpc64le) + + # MIPS + (b == mips && isCompatible a mips64) + (b == mips && a == mipsel) + (b == mipsel && isCompatible a mips) + (b == mips64 && a == mips64el) + (b == mips64el && isCompatible a mips64) + + # RISCV + (b == riscv32 && isCompatible a riscv64) + + # SPARC + (b == sparc && isCompatible a sparc64) + + # WASM + (b == wasm32 && isCompatible a wasm64) + + # identity + (b == a) + ]; + ################################################################################ types.openVendor = mkOptionType { @@ -147,6 +228,7 @@ rec { elf = {}; macho = {}; pe = {}; + wasm = {}; unknown = {}; }; @@ -189,6 +271,7 @@ rec { none = { execFormat = unknown; families = { }; }; openbsd = { execFormat = elf; families = { inherit bsd; }; }; solaris = { execFormat = elf; families = { }; }; + wasi = { execFormat = wasm; families = { }; }; windows = { execFormat = pe; families = { }; }; ghcjs = { execFormat = unknown; families = { }; }; } // { # aliases @@ -298,6 +381,8 @@ rec { then { cpu = elemAt l 0; kernel = elemAt l 1; abi = elemAt l 2; } else if (elemAt l 2 == "mingw32") # autotools breaks on -gnu for window then { cpu = elemAt l 0; vendor = elemAt l 1; kernel = "windows"; } + else if (elemAt l 2 == "wasi") + then { cpu = elemAt l 0; vendor = elemAt l 1; kernel = "wasi"; } else if hasPrefix "netbsd" (elemAt l 2) then { cpu = elemAt l 0; vendor = elemAt l 1; kernel = elemAt l 2; } else if (elem (elemAt l 2) ["eabi" "eabihf" "elf"]) @@ -348,7 +433,7 @@ rec { mkSystemFromString = s: mkSystemFromSkeleton (mkSkeletonFromList (lib.splitString "-" s)); - doubleFromSystem = { cpu, vendor, kernel, abi, ... }: + doubleFromSystem = { cpu, kernel, abi, ... }: /**/ if abi == abis.cygnus then "${cpu.name}-cygwin" else if kernel.families ? darwin then "${cpu.name}-darwin" else "${cpu.name}-${kernel.name}"; diff --git a/lib/systems/platforms.nix b/lib/systems/platforms.nix index 03bfce256103c..a2b43c970a411 100644 --- a/lib/systems/platforms.nix +++ b/lib/systems/platforms.nix @@ -253,22 +253,11 @@ rec { kernelTarget = "zImage"; }; - # https://developer.android.com/ndk/guides/abis#armeabi - armv5te-android = { - name = "armeabi"; - gcc = { - arch = "armv5te"; - float = "soft"; - float-abi = "soft"; - }; - }; - # https://developer.android.com/ndk/guides/abis#v7a armv7a-android = { name = "armeabi-v7a"; gcc = { arch = "armv7-a"; - float = "hard"; float-abi = "softfp"; fpu = "vfpv3-d16"; }; diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh index a72777cbf2a68..cf344122cf4e4 100755 --- a/lib/tests/modules.sh +++ b/lib/tests/modules.sh @@ -71,6 +71,15 @@ checkConfigError 'The option value .* in .* is not of type.*positive integer.*' checkConfigOutput "42" config.value ./declare-int-between-value.nix ./define-value-int-positive.nix checkConfigError 'The option value .* in .* is not of type.*between.*-21 and 43.*inclusive.*' config.value ./declare-int-between-value.nix ./define-value-int-negative.nix +# Check either types +# types.either +checkConfigOutput "42" config.value ./declare-either.nix ./define-value-int-positive.nix +checkConfigOutput "\"24\"" config.value ./declare-either.nix ./define-value-string.nix +# types.oneOf +checkConfigOutput "42" config.value ./declare-oneOf.nix ./define-value-int-positive.nix +checkConfigOutput "[ ]" config.value ./declare-oneOf.nix ./define-value-list.nix +checkConfigOutput "\"24\"" config.value ./declare-oneOf.nix ./define-value-string.nix + # Check mkForce without submodules. set -- config.enable ./declare-enable.nix ./define-enable.nix checkConfigOutput "true" "$@" @@ -149,7 +158,7 @@ checkConfigOutput "1 2 3 4 5 6 7 8 9 10" config.result ./loaOf-with-long-list.ni # Check loaOf with many merges of lists. checkConfigOutput "1 2 3 4 5 6 7 8 9 10" config.result ./loaOf-with-many-list-merges.nix -# Check mkAliasOptionModuleWithPriority. +# Check mkAliasOptionModule. checkConfigOutput "true" config.enable ./alias-with-priority.nix checkConfigOutput "true" config.enableAlias ./alias-with-priority.nix checkConfigOutput "false" config.enable ./alias-with-priority-can-override.nix diff --git a/lib/tests/modules/alias-with-priority-can-override.nix b/lib/tests/modules/alias-with-priority-can-override.nix index a6b26895f3a8d..9a18c9d9f613b 100644 --- a/lib/tests/modules/alias-with-priority-can-override.nix +++ b/lib/tests/modules/alias-with-priority-can-override.nix @@ -1,5 +1,8 @@ # This is a test to show that mkAliasOptionModule sets the priority correctly # for aliased options. +# +# This test shows that an alias with a high priority is able to override +# a non-aliased option. { config, lib, ... }: @@ -32,10 +35,10 @@ with lib; imports = [ # Create an alias for the "enable" option. - (mkAliasOptionModuleWithPriority [ "enableAlias" ] [ "enable" ]) + (mkAliasOptionModule [ "enableAlias" ] [ "enable" ]) - # Disable the aliased option, but with a default (low) priority so it - # should be able to be overridden by the next import. + # Disable the aliased option with a high priority so it + # should override the next import. ( { config, lib, ... }: { enableAlias = lib.mkForce false; diff --git a/lib/tests/modules/alias-with-priority.nix b/lib/tests/modules/alias-with-priority.nix index 923483684cb16..a35a06fc69749 100644 --- a/lib/tests/modules/alias-with-priority.nix +++ b/lib/tests/modules/alias-with-priority.nix @@ -1,5 +1,8 @@ # This is a test to show that mkAliasOptionModule sets the priority correctly # for aliased options. +# +# This test shows that an alias with a low priority is able to be overridden +# with a non-aliased option. { config, lib, ... }: @@ -32,7 +35,7 @@ with lib; imports = [ # Create an alias for the "enable" option. - (mkAliasOptionModuleWithPriority [ "enableAlias" ] [ "enable" ]) + (mkAliasOptionModule [ "enableAlias" ] [ "enable" ]) # Disable the aliased option, but with a default (low) priority so it # should be able to be overridden by the next import. diff --git a/lib/tests/modules/declare-either.nix b/lib/tests/modules/declare-either.nix new file mode 100644 index 0000000000000..5a0fa978a1381 --- /dev/null +++ b/lib/tests/modules/declare-either.nix @@ -0,0 +1,5 @@ +{ lib, ... }: { + options.value = lib.mkOption { + type = lib.types.either lib.types.int lib.types.str; + }; +} diff --git a/lib/tests/modules/declare-oneOf.nix b/lib/tests/modules/declare-oneOf.nix new file mode 100644 index 0000000000000..df092a14f81e2 --- /dev/null +++ b/lib/tests/modules/declare-oneOf.nix @@ -0,0 +1,9 @@ +{ lib, ... }: { + options.value = lib.mkOption { + type = lib.types.oneOf [ + lib.types.int + (lib.types.listOf lib.types.int) + lib.types.str + ]; + }; +} diff --git a/lib/tests/release.nix b/lib/tests/release.nix index d9a8a00672538..737d142d25324 100644 --- a/lib/tests/release.nix +++ b/lib/tests/release.nix @@ -1,11 +1,9 @@ { pkgs ? import ((import ../.).cleanSource ../..) {} }: -pkgs.stdenv.mkDerivation { - name = "nixpkgs-lib-tests"; - buildInputs = [ pkgs.nix ]; +pkgs.runCommandNoCC "nixpkgs-lib-tests" { + buildInputs = [ pkgs.nix (import ./check-eval.nix) ]; NIX_PATH="nixpkgs=${pkgs.path}"; - - buildCommand = '' +} '' datadir="${pkgs.nix}/share" export TEST_ROOT=$(pwd)/test-tmp export NIX_BUILD_HOOK= @@ -22,10 +20,5 @@ pkgs.stdenv.mkDerivation { cd ${pkgs.path}/lib/tests bash ./modules.sh - [[ "$(nix-instantiate --eval --strict misc.nix)" == "[ ]" ]] - - [[ "$(nix-instantiate --eval --strict systems.nix)" == "[ ]" ]] - touch $out - ''; -} +'' diff --git a/lib/tests/systems.nix b/lib/tests/systems.nix index 5e12936582159..5748c09b564d5 100644 --- a/lib/tests/systems.nix +++ b/lib/tests/systems.nix @@ -12,19 +12,19 @@ let expected = lib.sort lib.lessThan y; }; in with lib.systems.doubles; lib.runTests { - testall = mseteq all (linux ++ darwin ++ freebsd ++ openbsd ++ netbsd ++ illumos ++ windows); + testall = mseteq all (linux ++ darwin ++ freebsd ++ openbsd ++ netbsd ++ illumos ++ wasi ++ windows ++ embedded); - testarm = mseteq arm [ "armv5tel-linux" "armv6l-linux" "armv7l-linux" ]; - testi686 = mseteq i686 [ "i686-linux" "i686-freebsd" "i686-netbsd" "i686-openbsd" "i686-cygwin" "i686-windows" ]; + testarm = mseteq arm [ "armv5tel-linux" "armv6l-linux" "armv7l-linux" "arm-none" "armv7a-darwin" ]; + testi686 = mseteq i686 [ "i686-linux" "i686-freebsd" "i686-netbsd" "i686-openbsd" "i686-cygwin" "i686-windows" "i686-none" "i686-darwin" ]; testmips = mseteq mips [ "mipsel-linux" ]; - testx86_64 = mseteq x86_64 [ "x86_64-linux" "x86_64-darwin" "x86_64-freebsd" "x86_64-openbsd" "x86_64-netbsd" "x86_64-cygwin" "x86_64-solaris" "x86_64-windows" ]; + testx86_64 = mseteq x86_64 [ "x86_64-linux" "x86_64-darwin" "x86_64-freebsd" "x86_64-openbsd" "x86_64-netbsd" "x86_64-cygwin" "x86_64-solaris" "x86_64-windows" "x86_64-none" ]; testcygwin = mseteq cygwin [ "i686-cygwin" "x86_64-cygwin" ]; - testdarwin = mseteq darwin [ "x86_64-darwin" ]; + testdarwin = mseteq darwin [ "x86_64-darwin" "i686-darwin" "aarch64-darwin" "armv7a-darwin" ]; testfreebsd = mseteq freebsd [ "i686-freebsd" "x86_64-freebsd" ]; testgnu = mseteq gnu (linux /* ++ kfreebsd ++ ... */); testillumos = mseteq illumos [ "x86_64-solaris" ]; - testlinux = mseteq linux [ "i686-linux" "x86_64-linux" "armv5tel-linux" "armv6l-linux" "armv7l-linux" "aarch64-linux" "mipsel-linux" ]; + testlinux = mseteq linux [ "aarch64-linux" "armv5tel-linux" "armv6l-linux" "armv7l-linux" "i686-linux" "mipsel-linux" "riscv32-linux" "riscv64-linux" "x86_64-linux" "powerpc64le-linux" ]; testnetbsd = mseteq netbsd [ "i686-netbsd" "x86_64-netbsd" ]; testopenbsd = mseteq openbsd [ "i686-openbsd" "x86_64-openbsd" ]; testwindows = mseteq windows [ "i686-cygwin" "x86_64-cygwin" "i686-windows" "x86_64-windows" ]; diff --git a/lib/trivial.nix b/lib/trivial.nix index 17489311236d0..f2710a6f0338d 100644 --- a/lib/trivial.nix +++ b/lib/trivial.nix @@ -112,7 +112,7 @@ rec { # Function to call f: # Argument to check for null before passing it to `f` - a: if isNull a then a else f a; + a: if a == null then a else f a; # Pull in some builtins not included elsewhere. inherit (builtins) @@ -134,7 +134,7 @@ rec { On each release the first letter is bumped and a new animal is chosen starting with that new letter. */ - codeName = "Koi"; + codeName = "Loris"; /* Returns the current nixpkgs version suffix as string. */ versionSuffix = @@ -259,9 +259,10 @@ rec { # TODO: figure out a clever way to integrate location information from # something like __unsafeGetAttrPos. - warn = msg: builtins.trace "WARNING: ${msg}"; + warn = msg: builtins.trace "[1;31mwarning: ${msg}[0m"; info = msg: builtins.trace "INFO: ${msg}"; + showWarnings = warnings: res: lib.fold (w: x: warn w x) res warnings; ## Function annotations diff --git a/lib/types.nix b/lib/types.nix index 7a88e1b9e36be..bcb5de0c379b8 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -111,7 +111,7 @@ rec { name = "int"; description = "signed integer"; check = isInt; - merge = mergeOneOption; + merge = mergeEqualOption; }; # Specialized subdomains of int @@ -176,14 +176,14 @@ rec { name = "float"; description = "floating point number"; check = isFloat; - merge = mergeOneOption; + merge = mergeEqualOption; }; str = mkOptionType { name = "str"; description = "string"; check = isString; - merge = mergeOneOption; + merge = mergeEqualOption; }; strMatching = pattern: mkOptionType { @@ -217,7 +217,8 @@ rec { # Deprecated; should not be used because it quietly concatenates # strings, which is usually not what you want. - string = separatedString ""; + string = warn "types.string is deprecated because it quietly concatenates strings" + (separatedString ""); attrs = mkOptionType { name = "attrs"; @@ -243,7 +244,7 @@ rec { name = "path"; # Hacky: there is no ‘isPath’ primop. check = x: builtins.substring 0 1 (toString x) == "/"; - merge = mergeOneOption; + merge = mergeEqualOption; }; # drop this in the future: @@ -415,7 +416,7 @@ rec { name = "enum"; description = "one of ${concatMapStringsSep ", " show values}"; check = flip elem values; - merge = mergeOneOption; + merge = mergeEqualOption; functor = (defaultFunctor name) // { payload = values; binOp = a: b: unique (a ++ b); }; }; @@ -443,6 +444,13 @@ rec { functor = (defaultFunctor name) // { wrapped = [ t1 t2 ]; }; }; + # Any of the types in the given list + oneOf = ts: + let + head' = if ts == [] then throw "types.oneOf needs to get at least one type in its argument" else head ts; + tail' = tail ts; + in foldl' either head' tail'; + # Either value of type `finalType` or `coercedType`, the latter is # converted to `finalType` using `coerceFunc`. coercedTo = coercedType: coerceFunc: finalType: @@ -469,8 +477,10 @@ rec { # Obsolete alternative to configOf. It takes its option # declarations from the ‘options’ attribute of containing option # declaration. - optionSet = builtins.throw "types.optionSet is deprecated; use types.submodule instead" "optionSet"; - + optionSet = mkOptionType { + name = builtins.trace "types.optionSet is deprecated; use types.submodule instead" "optionSet"; + description = "option set"; + }; # Augment the given type with an additional type check function. addCheck = elemType: check: elemType // { check = x: elemType.check x && check x; }; |