-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
lib/types: fix either lazy value regression in case of non-matching v… #438558
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { lib, ... }: | ||
| { | ||
| # Proper type would be attrsOf (either int str) | ||
| # This checks backwards compatibility for the incorrect usage of either | ||
| freeformType = lib.types.either lib.types.int lib.types.str; | ||
| foo = "bar"; | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -106,6 +106,14 @@ let | |||||
| in | ||||||
| if invalidDefs != [ ] then { message = "Definition values: ${showDefs invalidDefs}"; } else null; | ||||||
|
|
||||||
| # Compat helper for merge to safely access the .value of merge.v2 | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The old type interface also allowed the merged value to be accessed without checking the definitions. It was the module system's responsibility to throw the definition errors, so the caller's responsibility.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, did some more analysis and I think we should consider this to be two problems at once, the combination of which allowed this to go undetected for a while.
I've started an alternate fix in #439189 with fewer workarounds. Ideally all workarounds are easy to clean up and we don't add workarounds that other code may accidentally start to rely on. |
||||||
| checkHeadError = | ||||||
| loc: descr: checkedAndMerged: | ||||||
| if checkedAndMerged.headError or null != null then | ||||||
| throw "A definition for option `${showOption loc}' is not of type `${descr}'. TypeError: ${checkedAndMerged.headError.message}" | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This has a fictional identifier "TypeError", which could be confusing.
Suggested change
|
||||||
| else | ||||||
| checkedAndMerged.value; | ||||||
|
|
||||||
| outer_types = rec { | ||||||
| isType = type: x: (x._type or "") == type; | ||||||
|
|
||||||
|
|
@@ -715,7 +723,7 @@ let | |||||
| merge = { | ||||||
| __functor = | ||||||
| self: loc: defs: | ||||||
| (self.v2 { inherit loc defs; }).value; | ||||||
| checkHeadError loc description (self.v2 { inherit loc defs; }); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These could turn out to be a problem, as they don't follow the original interface. |
||||||
| v2 = | ||||||
| { loc, defs }: | ||||||
| let | ||||||
|
|
@@ -828,7 +836,7 @@ let | |||||
| merge = { | ||||||
| __functor = | ||||||
| self: loc: defs: | ||||||
| (self.v2 { inherit loc defs; }).value; | ||||||
| checkHeadError loc description (self.v2 { inherit loc defs; }); | ||||||
| v2 = | ||||||
| { loc, defs }: | ||||||
| let | ||||||
|
|
@@ -1252,7 +1260,7 @@ let | |||||
| merge = { | ||||||
| __functor = | ||||||
| self: loc: defs: | ||||||
| (self.v2 { inherit loc defs; }).value; | ||||||
| checkHeadError loc description (self.v2 { inherit loc defs; }); | ||||||
| v2 = | ||||||
| { loc, defs }: | ||||||
| let | ||||||
|
|
@@ -1417,7 +1425,16 @@ let | |||||
| merge = { | ||||||
| __functor = | ||||||
| self: loc: defs: | ||||||
| (self.v2 { inherit loc defs; }).value; | ||||||
| let | ||||||
| cm = (self.v2 { inherit loc defs; }); | ||||||
| in | ||||||
| if cm.headError ? fallback then | ||||||
| lib.warn ( | ||||||
| cm.headError.message | ||||||
| + "\nIf you are the module maintainer, please fix the type. This will be turned into an error after 26.05" | ||||||
| ) cm.headError.fallback | ||||||
| else | ||||||
| checkHeadError loc description cm; | ||||||
| v2 = | ||||||
| { loc, defs }: | ||||||
| let | ||||||
|
|
@@ -1452,6 +1469,9 @@ let | |||||
| }; | ||||||
| headError = { | ||||||
| message = "The option `${showOption loc}` is neither a value of type `${t1.description}` nor `${t2.description}`, Definition values: ${showDefs defs}"; | ||||||
| # Specific for either, to ease migrations | ||||||
| # until 26.05 this is a warning, afterwards it will be removed | ||||||
| fallback = mergeOneOption loc defs; | ||||||
| }; | ||||||
| value = abort "(t.merge.v2 defs).value must only be accessed when `.headError == null`. This is a bug in code that consumes a module system type."; | ||||||
| }; | ||||||
|
|
@@ -1501,7 +1521,7 @@ let | |||||
| merge = { | ||||||
| __functor = | ||||||
| self: loc: defs: | ||||||
| (self.v2 { inherit loc defs; }).value; | ||||||
| checkHeadError loc description (self.v2 { inherit loc defs; }); | ||||||
| v2 = | ||||||
| { loc, defs }: | ||||||
| let | ||||||
|
|
@@ -1568,7 +1588,7 @@ let | |||||
| merge = { | ||||||
| __functor = | ||||||
| self: loc: defs: | ||||||
| (self.v2 { inherit loc defs; }).value; | ||||||
| checkHeadError loc elemType.description (self.v2 { inherit loc defs; }); | ||||||
| v2 = | ||||||
| { loc, defs }: | ||||||
| let | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.