libexpr: Deprecate or in non-keyword positions
Test cases courtesy of rhenrdic Co-authored-by: Commentator2.0 <lix@crystal-cavern.systems> Change-Id: Id8df684ddd00d07b49e1c9e68bf41ee6c0e6887c
This commit is contained in:
co-authored by
Commentator2.0
parent
af166146ff
commit
17f1bcfd2c
@@ -1,7 +1,7 @@
|
||||
---
|
||||
synopsis: 'more deprecated features'
|
||||
issues: []
|
||||
cls: [2092, 2310, 2311, 4638, 4652]
|
||||
cls: [2092, 2310, 2311, 4638, 4652, 4764]
|
||||
category: Breaking Changes
|
||||
credits: [piegames, commentator2.0]
|
||||
---
|
||||
@@ -13,3 +13,4 @@ You can opt in into the old behavior with `--extra-deprecated-features` or any e
|
||||
- `floating-without-zero` so far, one was able to declare a float using something like `.123`. This can cause confusion about accessing attributes. Floating point numbers must now always include the leading zero, i.e. `0.123`
|
||||
- `rec-set-merges` Attribute sets like `{ foo = {}; foo.bar = 42;}` implicitly merge at parse time, however if one of them is marked as recursive but not the others then the recursive attribute may get lost (order-dependent). Therefore, merging attrs with mixed-`rec` is now forbidden.
|
||||
- `rec-set-dynamic-attrs` Dynamic attributes have weird semantics in the presence of recursive attrsets (they evaluate *after* the rest of the set). This is now forbidden.
|
||||
- `or-as-identifier` `or` as an identifier has always been weird since the `or` (almost-)keyword has been introduced. We are deprecating the backcompat hacks from the early days of Nix in favor of making `or` a full and proper keyword.
|
||||
|
||||
@@ -324,7 +324,11 @@ struct AttrState : SubexprState {
|
||||
|
||||
template<> struct BuildAST<grammar::v1::attr::simple> {
|
||||
static void apply(const auto & in, auto & s, State & ps) {
|
||||
s.pushAttr(ps.symbols.create(in.string_view()), ps.at(in));
|
||||
auto symbol = ps.symbols.create(in.string_view());
|
||||
if (!ps.featureSettings.isEnabled(Dep::OrAsIdentifier) && symbol == ps.symbols.sym_or) {
|
||||
ps.orIdentifierFound(ps.at(in));
|
||||
}
|
||||
s.pushAttr(symbol, ps.at(in));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -956,6 +960,10 @@ template<> struct BuildAST<grammar::v1::expr::select::attr_or> {
|
||||
|
||||
template<> struct BuildAST<grammar::v1::expr::select::as_app_or> {
|
||||
static void apply(const auto & in, SelectState & s, State & ps) {
|
||||
if (!ps.featureSettings.isEnabled(Dep::OrAsIdentifier)) {
|
||||
ps.orArgumentFound(ps.at(in));
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Expr>> args(1);
|
||||
args[0] = std::make_unique<ExprVar>(ps.at(in), ps.symbols.sym_or);
|
||||
s->emplaceExpr<ExprCall>(s.pos, s->popExprOnly(), std::move(args));
|
||||
|
||||
@@ -42,6 +42,8 @@ struct State
|
||||
void nulFound(const PosIdx pos);
|
||||
void recSetMergeFound(const AttrPath & attrPath, const PosIdx pos);
|
||||
void recSetDynamicAttrFound(const PosIdx pos);
|
||||
void orIdentifierFound(const PosIdx pos);
|
||||
void orArgumentFound(const PosIdx pos);
|
||||
void addAttr(ExprAttrs * attrs, AttrPath && attrPath, std::unique_ptr<Expr> e, const PosIdx pos);
|
||||
void mergeAttrs(AttrPath & attrPath, ExprSet * source, ExprSet * target);
|
||||
void validateLambdaAttrs(AttrsPattern & pattern, PosIdx pos = noPos);
|
||||
@@ -198,6 +200,34 @@ inline void State::recSetDynamicAttrFound(const PosIdx pos)
|
||||
});
|
||||
}
|
||||
|
||||
// Added 2026-01-30
|
||||
inline void State::orIdentifierFound(const PosIdx pos)
|
||||
{
|
||||
logWarning({
|
||||
.msg = HintFmt(
|
||||
"using %s as an identifier is deprecated because it cannot be used in most places (try "
|
||||
"%s). Use %s to disable this warning.",
|
||||
"or",
|
||||
"let or = 1; in or",
|
||||
"--extra-deprecated-features or-as-identifier"
|
||||
),
|
||||
.pos = positions[pos],
|
||||
});
|
||||
}
|
||||
// Added 2026-01-30
|
||||
inline void State::orArgumentFound(const PosIdx pos)
|
||||
{
|
||||
logWarning({
|
||||
.msg = HintFmt(
|
||||
"using %s as an argument is deprecated because it is parsed with the wrong precedence "
|
||||
"which may cause unexpected behavior. Use %s to disable this warning.",
|
||||
"or",
|
||||
"--extra-deprecated-features or-as-identifier"
|
||||
),
|
||||
.pos = positions[pos],
|
||||
});
|
||||
}
|
||||
|
||||
inline void State::addAttr(ExprAttrs * attrs, AttrPath && attrPath, std::unique_ptr<Expr> e, const PosIdx pos)
|
||||
{
|
||||
AttrPath::iterator i;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
name: or-as-identifier
|
||||
internalName: OrAsIdentifier
|
||||
timeline:
|
||||
- date: 2026-01-30
|
||||
release: 2.95.0
|
||||
cls: [4764]
|
||||
message: Introduced as a warning.
|
||||
---
|
||||
Back when the `or` operator was introduced, instead of making it a proper keyword, the syntax was adapted in attempt of making it a context-sensitive keyword without disrupting existing code.
|
||||
This attempt has backfired, because it causes glitches in the operator precedence when a variable is called `or`:
|
||||
`let or = 1; in [ (x: x) or ]` evaluates to a list with one element, but `let nor = 1; in [ (x: x) nor ]` evaluates to a list with two elements.
|
||||
These old backwards compatibility hacks are deprecated in favor of treating `or` as a full language keyword.
|
||||
|
||||
To fix this, rename affected attributes or put the attribute name in quotes (`"or"`).
|
||||
@@ -181,6 +181,7 @@ deprecated_feature_definitions = files(
|
||||
'deprecated-features/floating-without-zero.md',
|
||||
'deprecated-features/nix-path-shadow.md',
|
||||
'deprecated-features/nul-bytes.md',
|
||||
'deprecated-features/or-as-identifier.md',
|
||||
'deprecated-features/rec-set-dynamic-attrs.md',
|
||||
'deprecated-features/rec-set-merges.md',
|
||||
'deprecated-features/rec-set-overrides.md',
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
let or = 1; in 1 or
|
||||
@@ -0,0 +1 @@
|
||||
let or = 1; in [ (x: x) or ]
|
||||
@@ -0,0 +1,8 @@
|
||||
let
|
||||
x = 2;
|
||||
or = 2;
|
||||
in
|
||||
[
|
||||
builtins.add 1 x
|
||||
builtins.add 1 or
|
||||
]
|
||||
@@ -0,0 +1,8 @@
|
||||
let
|
||||
x = 2;
|
||||
or = 2;
|
||||
in
|
||||
[
|
||||
[ 1 x ]
|
||||
[ 1 or ]
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
let or = 1; in { a = 2; }.a or (x: x) or
|
||||
@@ -0,0 +1,15 @@
|
||||
_type: ExprLet
|
||||
attrs:
|
||||
or:
|
||||
_type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
body:
|
||||
_type: ExprCall
|
||||
args:
|
||||
- _type: ExprVar
|
||||
value: or
|
||||
fun:
|
||||
_type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
@@ -0,0 +1,19 @@
|
||||
_type: ExprLet
|
||||
attrs:
|
||||
or:
|
||||
_type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
body:
|
||||
_type: ExprList
|
||||
elems:
|
||||
- _type: ExprCall
|
||||
args:
|
||||
- _type: ExprVar
|
||||
value: or
|
||||
fun:
|
||||
_type: ExprLambda
|
||||
arg: x
|
||||
body:
|
||||
_type: ExprVar
|
||||
value: x
|
||||
@@ -0,0 +1,38 @@
|
||||
_type: ExprLet
|
||||
attrs:
|
||||
or:
|
||||
_type: ExprLiteral
|
||||
value: 2
|
||||
valueType: Int
|
||||
x:
|
||||
_type: ExprLiteral
|
||||
value: 2
|
||||
valueType: Int
|
||||
body:
|
||||
_type: ExprList
|
||||
elems:
|
||||
- _type: ExprSelect
|
||||
attrs:
|
||||
- add
|
||||
e:
|
||||
_type: ExprVar
|
||||
value: builtins
|
||||
- _type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
- _type: ExprVar
|
||||
value: x
|
||||
- _type: ExprSelect
|
||||
attrs:
|
||||
- add
|
||||
e:
|
||||
_type: ExprVar
|
||||
value: builtins
|
||||
- _type: ExprCall
|
||||
args:
|
||||
- _type: ExprVar
|
||||
value: or
|
||||
fun:
|
||||
_type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
@@ -0,0 +1,30 @@
|
||||
_type: ExprLet
|
||||
attrs:
|
||||
or:
|
||||
_type: ExprLiteral
|
||||
value: 2
|
||||
valueType: Int
|
||||
x:
|
||||
_type: ExprLiteral
|
||||
value: 2
|
||||
valueType: Int
|
||||
body:
|
||||
_type: ExprList
|
||||
elems:
|
||||
- _type: ExprList
|
||||
elems:
|
||||
- _type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
- _type: ExprVar
|
||||
value: x
|
||||
- _type: ExprList
|
||||
elems:
|
||||
- _type: ExprCall
|
||||
args:
|
||||
- _type: ExprVar
|
||||
value: or
|
||||
fun:
|
||||
_type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
@@ -0,0 +1,29 @@
|
||||
_type: ExprLet
|
||||
attrs:
|
||||
or:
|
||||
_type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
body:
|
||||
_type: ExprSelect
|
||||
attrs:
|
||||
- a
|
||||
default:
|
||||
_type: ExprCall
|
||||
args:
|
||||
- _type: ExprVar
|
||||
value: or
|
||||
fun:
|
||||
_type: ExprLambda
|
||||
arg: x
|
||||
body:
|
||||
_type: ExprVar
|
||||
value: x
|
||||
e:
|
||||
_type: ExprSet
|
||||
attrs:
|
||||
a:
|
||||
_type: ExprLiteral
|
||||
value: 2
|
||||
valueType: Int
|
||||
recursive: false
|
||||
@@ -0,0 +1,9 @@
|
||||
[[test]]
|
||||
runner = "parse-okay"
|
||||
flags = ["--extra-deprecated-features", "or-as-identifier"]
|
||||
matrix = true
|
||||
|
||||
[[test]]
|
||||
name = "warning"
|
||||
runner = "parse-okay"
|
||||
matrix = true
|
||||
@@ -0,0 +1,10 @@
|
||||
warning: using or as an identifier is deprecated because it cannot be used in most places (try let or = 1; in or). Use --extra-deprecated-features or-as-identifier to disable this warning.
|
||||
at /pwd/in.nix:1:5:
|
||||
1| let or = 1; in 1 or
|
||||
| ^
|
||||
2|
|
||||
warning: using or as an argument is deprecated because it is parsed with the wrong precedence which may cause unexpected behavior. Use --extra-deprecated-features or-as-identifier to disable this warning.
|
||||
at /pwd/in.nix:1:18:
|
||||
1| let or = 1; in 1 or
|
||||
| ^
|
||||
2|
|
||||
@@ -0,0 +1,15 @@
|
||||
_type: ExprLet
|
||||
attrs:
|
||||
or:
|
||||
_type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
body:
|
||||
_type: ExprCall
|
||||
args:
|
||||
- _type: ExprVar
|
||||
value: or
|
||||
fun:
|
||||
_type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
@@ -0,0 +1,10 @@
|
||||
warning: using or as an identifier is deprecated because it cannot be used in most places (try let or = 1; in or). Use --extra-deprecated-features or-as-identifier to disable this warning.
|
||||
at /pwd/in.nix:1:5:
|
||||
1| let or = 1; in [ (x: x) or ]
|
||||
| ^
|
||||
2|
|
||||
warning: using or as an argument is deprecated because it is parsed with the wrong precedence which may cause unexpected behavior. Use --extra-deprecated-features or-as-identifier to disable this warning.
|
||||
at /pwd/in.nix:1:25:
|
||||
1| let or = 1; in [ (x: x) or ]
|
||||
| ^
|
||||
2|
|
||||
@@ -0,0 +1,19 @@
|
||||
_type: ExprLet
|
||||
attrs:
|
||||
or:
|
||||
_type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
body:
|
||||
_type: ExprList
|
||||
elems:
|
||||
- _type: ExprCall
|
||||
args:
|
||||
- _type: ExprVar
|
||||
value: or
|
||||
fun:
|
||||
_type: ExprLambda
|
||||
arg: x
|
||||
body:
|
||||
_type: ExprVar
|
||||
value: x
|
||||
@@ -0,0 +1,12 @@
|
||||
warning: using or as an identifier is deprecated because it cannot be used in most places (try let or = 1; in or). Use --extra-deprecated-features or-as-identifier to disable this warning.
|
||||
at /pwd/in.nix:3:5:
|
||||
2| x = 2;
|
||||
3| or = 2;
|
||||
| ^
|
||||
4| in
|
||||
warning: using or as an argument is deprecated because it is parsed with the wrong precedence which may cause unexpected behavior. Use --extra-deprecated-features or-as-identifier to disable this warning.
|
||||
at /pwd/in.nix:7:24:
|
||||
6| builtins.add 1 x
|
||||
7| builtins.add 1 or
|
||||
| ^
|
||||
8| ]
|
||||
@@ -0,0 +1,38 @@
|
||||
_type: ExprLet
|
||||
attrs:
|
||||
or:
|
||||
_type: ExprLiteral
|
||||
value: 2
|
||||
valueType: Int
|
||||
x:
|
||||
_type: ExprLiteral
|
||||
value: 2
|
||||
valueType: Int
|
||||
body:
|
||||
_type: ExprList
|
||||
elems:
|
||||
- _type: ExprSelect
|
||||
attrs:
|
||||
- add
|
||||
e:
|
||||
_type: ExprVar
|
||||
value: builtins
|
||||
- _type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
- _type: ExprVar
|
||||
value: x
|
||||
- _type: ExprSelect
|
||||
attrs:
|
||||
- add
|
||||
e:
|
||||
_type: ExprVar
|
||||
value: builtins
|
||||
- _type: ExprCall
|
||||
args:
|
||||
- _type: ExprVar
|
||||
value: or
|
||||
fun:
|
||||
_type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
@@ -0,0 +1,12 @@
|
||||
warning: using or as an identifier is deprecated because it cannot be used in most places (try let or = 1; in or). Use --extra-deprecated-features or-as-identifier to disable this warning.
|
||||
at /pwd/in.nix:3:5:
|
||||
2| x = 2;
|
||||
3| or = 2;
|
||||
| ^
|
||||
4| in
|
||||
warning: using or as an argument is deprecated because it is parsed with the wrong precedence which may cause unexpected behavior. Use --extra-deprecated-features or-as-identifier to disable this warning.
|
||||
at /pwd/in.nix:7:13:
|
||||
6| [ 1 x ]
|
||||
7| [ 1 or ]
|
||||
| ^
|
||||
8| ]
|
||||
@@ -0,0 +1,30 @@
|
||||
_type: ExprLet
|
||||
attrs:
|
||||
or:
|
||||
_type: ExprLiteral
|
||||
value: 2
|
||||
valueType: Int
|
||||
x:
|
||||
_type: ExprLiteral
|
||||
value: 2
|
||||
valueType: Int
|
||||
body:
|
||||
_type: ExprList
|
||||
elems:
|
||||
- _type: ExprList
|
||||
elems:
|
||||
- _type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
- _type: ExprVar
|
||||
value: x
|
||||
- _type: ExprList
|
||||
elems:
|
||||
- _type: ExprCall
|
||||
args:
|
||||
- _type: ExprVar
|
||||
value: or
|
||||
fun:
|
||||
_type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
@@ -0,0 +1,10 @@
|
||||
warning: using or as an identifier is deprecated because it cannot be used in most places (try let or = 1; in or). Use --extra-deprecated-features or-as-identifier to disable this warning.
|
||||
at /pwd/in.nix:1:5:
|
||||
1| let or = 1; in { a = 2; }.a or (x: x) or
|
||||
| ^
|
||||
2|
|
||||
warning: using or as an argument is deprecated because it is parsed with the wrong precedence which may cause unexpected behavior. Use --extra-deprecated-features or-as-identifier to disable this warning.
|
||||
at /pwd/in.nix:1:39:
|
||||
1| let or = 1; in { a = 2; }.a or (x: x) or
|
||||
| ^
|
||||
2|
|
||||
@@ -0,0 +1,29 @@
|
||||
_type: ExprLet
|
||||
attrs:
|
||||
or:
|
||||
_type: ExprLiteral
|
||||
value: 1
|
||||
valueType: Int
|
||||
body:
|
||||
_type: ExprSelect
|
||||
attrs:
|
||||
- a
|
||||
default:
|
||||
_type: ExprCall
|
||||
args:
|
||||
- _type: ExprVar
|
||||
value: or
|
||||
fun:
|
||||
_type: ExprLambda
|
||||
arg: x
|
||||
body:
|
||||
_type: ExprVar
|
||||
value: x
|
||||
e:
|
||||
_type: ExprSet
|
||||
attrs:
|
||||
a:
|
||||
_type: ExprLiteral
|
||||
value: 2
|
||||
valueType: Int
|
||||
recursive: false
|
||||
@@ -0,0 +1,12 @@
|
||||
warning: using or as an identifier is deprecated because it cannot be used in most places (try let or = 1; in or). Use --extra-deprecated-features or-as-identifier to disable this warning.
|
||||
at /pwd/in.nix:9:3:
|
||||
8|
|
||||
9| or = x: y: x || y;
|
||||
| ^
|
||||
10|
|
||||
warning: using or as an argument is deprecated because it is parsed with the wrong precedence which may cause unexpected behavior. Use --extra-deprecated-features or-as-identifier to disable this warning.
|
||||
at /pwd/in.nix:23:11:
|
||||
22| # it short-circuits and never runs into the type error
|
||||
23| (fold or [] [true false false])
|
||||
| ^
|
||||
24| ]
|
||||
@@ -0,0 +1 @@
|
||||
with {}; or
|
||||
@@ -0,0 +1 @@
|
||||
let or = 1; in or
|
||||
@@ -0,0 +1,5 @@
|
||||
error: syntax error, expecting expression
|
||||
at /pwd/in.nix:1:10:
|
||||
1| with {}; or
|
||||
| ^
|
||||
2|
|
||||
@@ -0,0 +1,10 @@
|
||||
warning: using or as an identifier is deprecated because it cannot be used in most places (try let or = 1; in or). Use --extra-deprecated-features or-as-identifier to disable this warning.
|
||||
at /pwd/in.nix:1:5:
|
||||
1| let or = 1; in or
|
||||
| ^
|
||||
2|
|
||||
error: syntax error, expecting expression
|
||||
at /pwd/in.nix:1:16:
|
||||
1| let or = 1; in or
|
||||
| ^
|
||||
2|
|
||||
@@ -15,6 +15,7 @@ let
|
||||
"broken-string-escape"
|
||||
"rec-set-merges"
|
||||
"rec-set-dynamic-attrs"
|
||||
"or-as-identifier"
|
||||
];
|
||||
in
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ let
|
||||
"broken-string-escape"
|
||||
"rec-set-merges"
|
||||
"rec-set-dynamic-attrs"
|
||||
"or-as-identifier"
|
||||
];
|
||||
|
||||
env.NIX_CONFIG = "extra-deprecated-features = ${concatStringsSep " " deprecatedFeatures}";
|
||||
|
||||
Reference in New Issue
Block a user