Skip to content

Commit

Permalink
Expr: Types: Binding(Inherit): NKeyName -> VarName
Browse files Browse the repository at this point in the history
Thread: #377 (comment)

`inherit x y` in y` position always takes a variable name.

Nix allows `inherit x "y"`, but there is no use (in the wild real life use) for
it, it seems a misfeature and would be considered a quirk of the original type
system/implementation, until the use case of it would be clear (which is hard,
since there is a single use of it in Nixpkgs, which is mentioned in the thread).
  • Loading branch information
Anton-Latukha committed Jul 21, 2021
1 parent f81830b commit a6d9f3e
Show file tree
Hide file tree
Showing 11 changed files with 51 additions and 53 deletions.
5 changes: 4 additions & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ Partial log (for now):
* Breaking:

* `Nix.Expr.Shorthands`:
* `inherit{,From}`: dropped second argument as irrelevant ([report](https://github.com/haskell-nix/hnix/issues/326)).
* `inherit{,From}`:
* dropped second(/third) argument as irrelevant ([report](https://github.com/haskell-nix/hnix/issues/326))
* bindings to inherit changed type from complex `[NKeyName]` (which is for static & dynamic keys) to `[VarName]` (`VarName` is newtype of `Text`).
* So examples of use now are: `inherit ["a", "b"]`, `inheritFrom (var "a") ["b", "c"]`
* `mkAssert`: fixed ([report](https://github.com/haskell-nix/hnix/issues/969)).
* fx presedence between the operators:

Expand Down
47 changes: 19 additions & 28 deletions src/Nix/Eval.hs
Original file line number Diff line number Diff line change
Expand Up @@ -369,36 +369,27 @@ evalBinds recursive binds =
=<< evalSetterKeyName h

applyBindToAdt scopes (Inherit ms names pos) =
catMaybes <$>
traverse
processScope
names
pure $ processScope <$> names
where
processScope
:: NKeyName (m v)
-> m (Maybe ([VarName], SourcePos, m v))
processScope nkeyname =
(\ mkey ->
do
key <- mkey
pure
([key]
, pos
, maybe
(attrMissing (key :| mempty) Nothing)
demand
=<< maybe
(withScopes scopes $ lookupVar key)
(\ s ->
do
(coerce -> scope, _) <- fromValue @(AttrSet v, PositionSet) =<< s

clearScopes @v $ pushScope scope $ lookupVar key
)
ms
)
) <$>
evalSetterKeyName nkeyname
:: VarName
-> ([VarName], SourcePos, m v)
processScope var =
([var]
, pos
, maybe
(attrMissing (var :| mempty) Nothing)
demand
=<< maybe
(withScopes scopes $ lookupVar var)
(\ s ->
do
(coerce -> scope, _) <- fromValue @(AttrSet v, PositionSet) =<< s

clearScopes @v $ pushScope scope $ lookupVar var
)
ms
)

moveOverridesLast = uncurry (<>) . partition
(\case
Expand Down
4 changes: 2 additions & 2 deletions src/Nix/Expr/Shorthands.hs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ mkSynHoleF = NSynHole . coerce
-- | @inheritFrom x [a, b]@ | @inherit (x) a b;@ | @a = x.a;@ |
-- | | | @b = x.b;@ |
-- +------------------------+--------------------+------------+
inheritFrom :: e -> [NKeyName e] -> Binding e
inheritFrom :: e -> [VarName] -> Binding e
inheritFrom expr ks = Inherit (pure expr) ks nullPos

-- | An `inherit` clause without an expression to pull from.
Expand All @@ -278,7 +278,7 @@ inheritFrom expr ks = Inherit (pure expr) ks nullPos
-- | @inheritFrom [a, b]@ | @inherit a b;@ | @a = outside.a;@ |
-- | | | @b = outside.b;@ |
-- +----------------------+----------------+------------------+
inherit :: [NKeyName e] -> Binding e
inherit :: [VarName] -> Binding e
inherit ks = Inherit Nothing ks nullPos

-- | Nix @=@ (bind operator).
Expand Down
2 changes: 1 addition & 1 deletion src/Nix/Expr/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ data Binding r
-- ^ An explicit naming.
--
-- > NamedVar (StaticKey "x" :| [StaticKey "y"]) z SourcePos{} ~ x.y = z;
| Inherit !(Maybe r) ![NKeyName r] !SourcePos
| Inherit !(Maybe r) ![VarName] !SourcePos
-- ^ Inheriting an attribute (binding) into the attribute set from the other scope (attribute set). No denoted scope means to inherit from the closest outside scope.
--
-- +---------------------------------------------------------------+--------------------+-----------------------+
Expand Down
2 changes: 1 addition & 1 deletion src/Nix/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ nixBinders = (inherit <+> namedVar) `endBy` semi where
p <- getSourcePos
x <- whiteSpace *> optional scope
liftA2 (Inherit x)
(many keyName)
(many identifier)
(pure p)
<?> "inherited binding"
namedVar =
Expand Down
2 changes: 1 addition & 1 deletion src/Nix/Pretty.hs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ prettyBind :: Binding (NixDoc ann) -> Doc ann
prettyBind (NamedVar n v _p) =
prettySelector n <> " = " <> withoutParens v <> ";"
prettyBind (Inherit s ns _p) =
"inherit " <> scope <> align (fillSep $ prettyKeyName <$> ns) <> ";"
"inherit " <> scope <> align (fillSep $ prettyVarName <$> ns) <> ";"
where
scope =
maybe
Expand Down
2 changes: 1 addition & 1 deletion src/Nix/Reduce.hs
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ pruneTree opts =
pruneBinding (NamedVar xs (Just x) pos) = pure $ NamedVar (pruneKeyName <$> xs) x pos
pruneBinding (Inherit _ [] _ ) = Nothing
pruneBinding (Inherit (join -> Nothing) _ _ ) = Nothing
pruneBinding (Inherit (join -> m) xs pos) = pure $ Inherit m (pruneKeyName <$> xs) pos
pruneBinding (Inherit (join -> m) xs pos) = pure $ Inherit m xs pos

reducingEvalExpr
:: (Framed e m, Has e Options, Exception r, MonadCatch m, MonadIO m)
Expand Down
8 changes: 2 additions & 6 deletions src/Nix/TH.hs
Original file line number Diff line number Diff line change
Expand Up @@ -104,22 +104,18 @@ freeVars e = case unFix e of
where
bind1Def :: Binding r -> Set VarName
bind1Def (Inherit Nothing _ _) = mempty
bind1Def (Inherit (Just _ ) keys _) = Set.fromList $ mapMaybe staticKey keys
bind1Def (Inherit (Just _ ) keys _) = Set.fromList keys
bind1Def (NamedVar (StaticKey varname :| _) _ _) = one varname
bind1Def (NamedVar (DynamicKey _ :| _) _ _) = mempty

bindFreeVars :: Foldable t => t (Binding NExpr) -> Set VarName
bindFreeVars = foldMap bind1Free
where
bind1Free :: Binding NExpr -> Set VarName
bind1Free (Inherit Nothing keys _) = Set.fromList $ mapMaybe staticKey keys
bind1Free (Inherit Nothing keys _) = Set.fromList keys
bind1Free (Inherit (Just scope) _ _) = freeVars scope
bind1Free (NamedVar path expr _) = pathFree path <> freeVars expr

staticKey :: NKeyName r -> Maybe VarName
staticKey (StaticKey varname) = pure varname
staticKey (DynamicKey _ ) = Nothing

pathFree :: NAttrPath NExpr -> Set VarName
pathFree = foldMap mapFreeVars

Expand Down
11 changes: 10 additions & 1 deletion tests/NixLanguageTests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,21 @@ newFailingTests = Set.fromList
, "eval-okay-fromTOML"
]

-- | Upstream tests that test cases that HNix disaded as a misfeature that is used so rarely
-- that it more effective to fix it & lint it out of existance.
deprecatedRareNixQuirkTests :: Set String
deprecatedRareNixQuirkTests = Set.fromList
[
-- A rare quirk of Nix that is proper to fix&enforce then to support (see git commit history)
"eval-okay-strings-as-attrs-names"
]

genTests :: IO TestTree
genTests = do
testFiles <-
sort
-- Disabling the not yet done tests cases.
. filter ((`Set.notMember` newFailingTests) . takeBaseName)
. filter ((`Set.notMember` (newFailingTests `Set.union` deprecatedRareNixQuirkTests)) . takeBaseName)
. filter ((/= ".xml") . takeExtension)
<$> globDir1 (compile "*-*-*.*") "data/nix/tests/lang"
let
Expand Down
17 changes: 8 additions & 9 deletions tests/ParserTests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ case_set_inherit =
checks
( mkNonRecSet
[ "e" $= mkInt 3
, inherit (StaticKey <$> ["a", "b"])
, inherit ["a", "b"]
]
, "{ e = 3; inherit a b; }"
)
Expand All @@ -197,7 +197,7 @@ case_set_scoped_inherit =
checks
( mkNonRecSet $
(\ x -> [x, "e" $= mkInt 4, x]) $
inheritFrom (var "a") (StaticKey <$> ["b", "c"])
inheritFrom (var "a") ["b", "c"]
, "{ inherit (a) b c; e = 4; inherit(a)b c; }"
)

Expand All @@ -207,15 +207,14 @@ case_set_inherit_direct =
, "{ inherit ({a = 3;}); }"
)

case_inherit_selector =
checks
( mkNonRecSet [inherit [DynamicKey (Plain (DoubleQuoted [Plain "a"]))]]
, "{ inherit \"a\"; }"
)

case_inherit_selector_syntax_mistakes =
mistakes
"{ inherit a.x; }"
( -- A rare quirk of Nix that is proper to fix then to support (see git commit history)
-- (old parser test result was):
-- mkNonRecSet [inherit [DynamicKey (Plain (DoubleQuoted [Plain "a"]))]],
"{ inherit \"a\"; }"
)


-- ** Lists
Expand Down Expand Up @@ -356,7 +355,7 @@ case_let_scoped_inherit =
checks
( mkLets
[ "a" $= mkNull
, inheritFrom (var "b") [StaticKey "c"]
, inheritFrom (var "b") $ one "c"
]
$ var "c"
, "let a = null; inherit (b) c; in c"
Expand Down
4 changes: 2 additions & 2 deletions tests/PrettyParseTests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ genBinding = Gen.choice
genSourcePos
, liftA3 Inherit
(Gen.maybe genExpr)
(Gen.list (Range.linear 0 5) genKeyName)
(Gen.list (Range.linear 0 5) (coerce <$> asciiText))
genSourcePos
]

Expand Down Expand Up @@ -170,7 +170,7 @@ normalize = foldFix $ \case

where
normBinding (NamedVar path r pos) = NamedVar (normKey <$> path) r pos
normBinding (Inherit mr names pos) = Inherit mr (normKey <$> names) pos
normBinding (Inherit mr names pos) = Inherit mr names pos

normKey (DynamicKey quoted) = DynamicKey (normAntiquotedString quoted)
normKey (StaticKey name ) = StaticKey name
Expand Down

0 comments on commit a6d9f3e

Please sign in to comment.