Skip to content

Commit

Permalink
Fix aliases to non-recursive names (#3203)
Browse files Browse the repository at this point in the history
* Closes #3201 
* As a side effect, aliases can now only be used after they are declared
(but they can still forward-reference identifiers, except the
non-recursive definitions or other aliases).
  • Loading branch information
lukaszcz authored Dec 1, 2024
1 parent 640d049 commit ad03334
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1696,26 +1696,8 @@ checkSections sec = topBindings helper
-- checks the definitions in a section
goDefsSection :: NonEmpty (Definition 'Parsed) -> Sem r' (NonEmpty (Definition 'Scoped))
goDefsSection defs = do
mapM_ scanAlias (defs ^.. each . _DefinitionSyntax . _SyntaxAlias)
mapM goDefinition defs

scanAlias :: AliasDef 'Parsed -> Sem r' ()
scanAlias a = do
aliasId <- gets (^?! scopeLocalSymbols . at (a ^. aliasDefName) . _Just . S.nameId)
asName <- checkName (a ^. aliasDefAsName)
modify' (set (scoperAlias . at aliasId) (Just asName))
checkLoop aliasId
registerAlias aliasId asName
where
checkLoop :: NameId -> Sem r' ()
checkLoop = evalState (mempty :: HashSet NameId) . go
where
go :: (Members '[State (HashSet NameId), Error ScoperError, State ScoperState] s) => NameId -> Sem s ()
go i = do
whenM (gets (HashSet.member i)) (throw (ErrAliasCycle (AliasCycle a)))
modify' (HashSet.insert i)
whenJustM (gets (^? scoperAlias . at i . _Just . preSymbolName . S.nameId)) go

reserveDefinition :: Definition 'Parsed -> Sem r' (Maybe (Module 'Parsed 'ModuleLocal))
reserveDefinition = \case
DefinitionSyntax s -> resolveSyntaxDef s $> Nothing
Expand Down Expand Up @@ -3253,7 +3235,7 @@ checkParsePatternAtom' ::
checkParsePatternAtom' = localBindings . ignoreSyntax . runReader PatternNamesKindVariables . checkParsePatternAtom

checkSyntaxDef ::
(Members '[Error ScoperError, Reader ScopeParameters, State Scope, State ScoperState, InfoTableBuilder, Reader InfoTable, NameIdGen, Reader PackageId, State ScoperSyntax] r) =>
(Members '[Error ScoperError, Reader ScopeParameters, State Scope, State ScoperState, Reader BindingStrategy, InfoTableBuilder, Reader InfoTable, NameIdGen, Reader PackageId, State ScoperSyntax] r) =>
SyntaxDef 'Parsed ->
Sem r (SyntaxDef 'Scoped)
checkSyntaxDef = \case
Expand All @@ -3263,10 +3245,12 @@ checkSyntaxDef = \case
SyntaxIterator iterDef -> return $ SyntaxIterator iterDef

checkAliasDef ::
(Members '[Error ScoperError, Reader ScopeParameters, State Scope, State ScoperState, InfoTableBuilder, Reader InfoTable, NameIdGen, State ScoperSyntax] r) =>
forall r.
(Members '[Error ScoperError, Reader ScopeParameters, State Scope, State ScoperState, Reader BindingStrategy, InfoTableBuilder, Reader InfoTable, NameIdGen, State ScoperSyntax] r) =>
AliasDef 'Parsed ->
Sem r (AliasDef 'Scoped)
checkAliasDef AliasDef {..} = do
checkAliasDef def@AliasDef {..} = do
scanAlias def
aliasName' :: S.Symbol <- gets (^?! scopeLocalSymbols . at _aliasDefName . _Just)
asName' <- checkScopedIden _aliasDefAsName
return
Expand All @@ -3275,6 +3259,14 @@ checkAliasDef AliasDef {..} = do
_aliasDefAsName = asName',
..
}
where
scanAlias :: AliasDef 'Parsed -> Sem r ()
scanAlias a = do
reserveAliasDef a
aliasId <- gets (^?! scopeLocalSymbols . at (a ^. aliasDefName) . _Just . S.nameId)
asName <- checkName (a ^. aliasDefAsName)
modify' (set (scoperAlias . at aliasId) (Just asName))
registerAlias aliasId asName

reserveAliasDef ::
(Members '[Error ScoperError, Reader ScopeParameters, State Scope, State ScoperState, InfoTableBuilder, Reader InfoTable, NameIdGen, State ScoperSyntax, Reader BindingStrategy] r) =>
Expand All @@ -3290,7 +3282,7 @@ resolveSyntaxDef = \case
SyntaxFixity fixDef -> resolveFixitySyntaxDef fixDef
SyntaxOperator opDef -> resolveOperatorSyntaxDef opDef
SyntaxIterator iterDef -> resolveIteratorSyntaxDef iterDef
SyntaxAlias a -> reserveAliasDef a
SyntaxAlias {} -> return ()

-------------------------------------------------------------------------------
-- Check precedences are comparable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ data ScoperError
| ErrMissingArgs MissingArgs
| ErrPrecedenceInconsistency PrecedenceInconsistencyError
| ErrIncomparablePrecedences IncomaprablePrecedences
| ErrAliasCycle AliasCycle
| ErrInvalidRangeNumber InvalidRangeNumber
| ErrWrongDefaultValue WrongDefaultValue
| ErrUnsupported Unsupported
Expand Down Expand Up @@ -104,7 +103,6 @@ instance ToGenericError ScoperError where
ErrMissingArgs e -> genericError e
ErrPrecedenceInconsistency e -> genericError e
ErrIncomparablePrecedences e -> genericError e
ErrAliasCycle e -> genericError e
ErrInvalidRangeNumber e -> genericError e
ErrWrongDefaultValue e -> genericError e
ErrUnsupported e -> genericError e
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1019,28 +1019,6 @@ instance ToGenericError IncomaprablePrecedences where
i :: Interval
i = getLoc _incomparablePrecedencesName1

newtype AliasCycle = AliasCycle
{ _aliasCycleDef :: AliasDef 'Parsed
}
deriving stock (Show)

instance ToGenericError AliasCycle where
genericError AliasCycle {..} = do
opts <- fromGenericOptions <$> ask
let msg =
"The definition of"
<+> ppCode opts (_aliasCycleDef ^. aliasDefName)
<+> "creates an alias cycle."
return
GenericError
{ _genericErrorLoc = i,
_genericErrorMessage = mkAnsiText msg,
_genericErrorIntervals = [i]
}
where
i :: Interval
i = getLoc _aliasCycleDef

newtype WrongDefaultValue = WrongDefaultValue
{ _wrongDefaultValue :: SigArg 'Parsed
}
Expand Down
4 changes: 2 additions & 2 deletions src/Juvix/Compiler/Core/Transformation/Optimize/Inlining.hs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ convertNode inlineDepth nonRecSyms md = dmapL go
node
_
| HashSet.member _identSymbol nonRecSyms
&& isInlineableLambda inlineDepth md bl def
&& length args >= argsNum ->
&& length args >= argsNum
&& isInlineableLambda inlineDepth md bl def ->
mkApps def args
_ ->
node
Expand Down
5 changes: 0 additions & 5 deletions test/Scope/Negative.hs
Original file line number Diff line number Diff line change
Expand Up @@ -269,11 +269,6 @@ scoperErrorTests =
$(mkRelDir ".")
$(mkRelFile "PrecedenceInconsistency.juvix")
$ wantsError ErrPrecedenceInconsistency,
negTest
"Alias cycle"
$(mkRelDir ".")
$(mkRelFile "AliasCycle.juvix")
$ wantsError ErrAliasCycle,
negTest
"Invalid range number in iterator definition"
$(mkRelDir ".")
Expand Down
5 changes: 0 additions & 5 deletions tests/negative/AliasCycle.juvix

This file was deleted.

17 changes: 16 additions & 1 deletion tests/positive/Alias.juvix
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ module Alias;

import Stdlib.Data.Fixity open;

-- aliases are allowed to forward reference
-- aliases are allowed to forward reference, but they themselves cannot be
-- forward referenced
syntax alias Boolean := Bool;
syntax alias ⊥ := false;
syntax alias ⊤ := true;
Expand Down Expand Up @@ -53,8 +54,22 @@ syntax alias , := mkPair;

myPair : Pair := one, ⊥;

syntax alias myPair' := myPair;

localAlias : Binary -> Binary
| b :=
let
syntax alias b' := b;
in b';

syntax alias g' := g;

terminating
f (b : Binary) : Binary := case b of
| zero := g' one
| one := zero;

terminating
g (b : Binary) : Binary := case b of
| zero := f one
| one := zero;

0 comments on commit ad03334

Please sign in to comment.