@@ -83,35 +83,39 @@ rec {
8383 # Default type merging function
8484 # takes two type functors and return the merged type
8585 defaultTypeMerge = f : f' :
86- let mergedWrapped = f . wrapped . typeMerge f' . wrapped . functor ;
87- mergedPayload = f . binOp f . payload f' . payload ;
86+ let
87+ mergedWrapped = f . wrapped . typeMerge f' . wrapped . functor ;
88+ mergedPayload = f . binOp f . payload f' . payload ;
8889
89- hasPayload = assert ( f' . payload != null ) == ( f . payload != null ) ; f . payload != null ;
90- hasWrapped = assert ( f' . wrapped != null ) == ( f . wrapped != null ) ; f . wrapped != null ;
90+ hasPayload = assert ( f' . payload != null ) == ( f . payload != null ) ; f . payload != null ;
91+ hasWrapped = assert ( f' . wrapped != null ) == ( f . wrapped != null ) ; f . wrapped != null ;
92+
93+ typeFromPayload = if mergedPayload == null then null else f . type mergedPayload ;
94+ typeFromWrapped = if mergedWrapped == null then null else f . type mergedWrapped ;
9195 in
9296 # Abort early: cannot merge different types
9397 if f . name != f' . name
9498 then null
9599 else
96100
97101 if hasPayload then
98- if hasWrapped then
102+ # Just return the payload if returning wrapped is deprecated
103+ if f ? wrappedDeprecationMessage then
104+ typeFromPayload
105+ else if hasWrapped then
99106 # Has both wrapped and payload
100107 throw ''
101108 Type ${ f . name } defines both `functor.payload` and `functor.wrapped` at the same time, which is not supported.
102109
103110 Use either `functor.payload` or `functor.wrapped` but not both.
104111
105- If your code worked before remove `functor.payload` from the type definition.
112+ If your code worked before remove either `functor.wrapped` or `functor.payload` from the type definition.
106113 ''
107114 else
108- # Has payload
109- if mergedPayload == null then null else f . type mergedPayload
115+ typeFromPayload
110116 else
111117 if hasWrapped then
112- # Has wrapped
113- # TODO(@hsjobeki): This could also be a warning and removed in the future
114- if mergedWrapped == null then null else f . type mergedWrapped
118+ typeFromWrapped
115119 else
116120 f . type ;
117121
@@ -582,48 +586,78 @@ rec {
582586 substSubModules = m : nonEmptyListOf ( elemType . substSubModules m ) ;
583587 } ;
584588
585- attrsOf = elemType : mkOptionType rec {
586- name = "attrsOf" ;
587- description = "attribute set of ${ optionDescriptionPhrase ( class : class == "noun" || class == "composite" ) elemType } " ;
588- descriptionClass = "composite" ;
589- check = isAttrs ;
590- merge = loc : defs :
591- mapAttrs ( n : v : v . value ) ( filterAttrs ( n : v : v ? value ) ( zipAttrsWith ( name : defs :
592- ( mergeDefinitions ( loc ++ [ name ] ) elemType defs ) . optionalValue
593- )
594- # Push down position info.
595- ( map ( def : mapAttrs ( n : v : { inherit ( def ) file ; value = v ; } ) def . value ) defs ) ) ) ;
596- emptyValue = { value = { } ; } ;
597- getSubOptions = prefix : elemType . getSubOptions ( prefix ++ [ "<name>" ] ) ;
598- getSubModules = elemType . getSubModules ;
599- substSubModules = m : attrsOf ( elemType . substSubModules m ) ;
600- functor = ( defaultFunctor name ) // { wrapped = elemType ; } ;
601- nestedTypes . elemType = elemType ;
602- } ;
589+ attrsOf = elemType : attrsWith { inherit elemType ; } ;
603590
604591 # A version of attrsOf that's lazy in its values at the expense of
605592 # conditional definitions not working properly. E.g. defining a value with
606593 # `foo.attr = mkIf false 10`, then `foo ? attr == true`, whereas with
607594 # attrsOf it would correctly be `false`. Accessing `foo.attr` would throw an
608595 # error that it's not defined. Use only if conditional definitions don't make sense.
609- lazyAttrsOf = elemType : mkOptionType rec {
610- name = "lazyAttrsOf" ;
611- description = "lazy attribute set of ${ optionDescriptionPhrase ( class : class == "noun" || class == "composite" ) elemType } " ;
596+ lazyAttrsOf = elemType : attrsWith { inherit elemType ; lazy = true ; } ;
597+
598+ # base type for lazyAttrsOf and attrsOf
599+ attrsWith =
600+ let
601+ # Push down position info.
602+ pushPositions = map ( def : mapAttrs ( n : v : { inherit ( def ) file ; value = v ; } ) def . value ) ;
603+ binOp = lhs : rhs :
604+ let
605+ elemType = lhs . elemType . typeMerge rhs . elemType . functor ;
606+ lazy =
607+ if lhs . lazy == rhs . lazy then
608+ lhs . lazy
609+ else
610+ null ;
611+ in
612+ if elemType == null || lazy == null then
613+ null
614+ else
615+ {
616+ inherit elemType lazy ;
617+ } ;
618+ in
619+ {
620+ elemType ,
621+ lazy ? false ,
622+ } :
623+ mkOptionType {
624+ name = if lazy then "lazyAttrsOf" else "attrsOf" ;
625+ description = ( if lazy then "lazy attribute set" else "attribute set" ) + " of ${ optionDescriptionPhrase ( class : class == "noun" || class == "composite" ) elemType } " ;
612626 descriptionClass = "composite" ;
613627 check = isAttrs ;
614- merge = loc : defs :
615- zipAttrsWith ( name : defs :
616- let merged = mergeDefinitions ( loc ++ [ name ] ) elemType defs ;
617- # mergedValue will trigger an appropriate error when accessed
618- in merged . optionalValue . value or elemType . emptyValue . value or merged . mergedValue
619- )
620- # Push down position info.
621- ( map ( def : mapAttrs ( n : v : { inherit ( def ) file ; value = v ; } ) def . value ) defs ) ;
628+ merge = if lazy then (
629+ # Lazy merge Function
630+ loc : defs :
631+ zipAttrsWith ( name : defs :
632+ let merged = mergeDefinitions ( loc ++ [ name ] ) elemType defs ;
633+ # mergedValue will trigger an appropriate error when accessed
634+ in merged . optionalValue . value or elemType . emptyValue . value or merged . mergedValue
635+ )
636+ # Push down position info.
637+ ( pushPositions defs )
638+ ) else (
639+ # Non-lazy merge Function
640+ loc : defs :
641+ mapAttrs ( n : v : v . value ) ( filterAttrs ( n : v : v ? value ) ( zipAttrsWith ( name : defs :
642+ ( mergeDefinitions ( loc ++ [ name ] ) elemType ( defs ) ) . optionalValue
643+ )
644+ # Push down position info.
645+ ( pushPositions defs ) ) )
646+ ) ;
622647 emptyValue = { value = { } ; } ;
623648 getSubOptions = prefix : elemType . getSubOptions ( prefix ++ [ "<name>" ] ) ;
624649 getSubModules = elemType . getSubModules ;
625- substSubModules = m : lazyAttrsOf ( elemType . substSubModules m ) ;
626- functor = ( defaultFunctor name ) // { wrapped = elemType ; } ;
650+ substSubModules = m : attrsWith { elemType = elemType . substSubModules m ; inherit lazy ; } ;
651+ functor = defaultFunctor "attrsWith" // {
652+ wrappedDeprecationMessage = { loc } : lib . warn ''
653+ The deprecated `type.functor.wrapped` attribute of the option `${ showOption loc } ` is accessed, use `type.nestedTypes.elemType` instead.
654+ '' elemType ;
655+ payload = {
656+ # Important!: Add new function attributes here in case of future changes
657+ inherit elemType lazy ;
658+ } ;
659+ inherit binOp ;
660+ } ;
627661 nestedTypes . elemType = elemType ;
628662 } ;
629663
0 commit comments