mirror of
https://github.com/anoma/juvix.git
synced 2024-12-01 00:04:58 +03:00
Add positivity check for inductive types (#1393)
* w.i.p * Added strict positivity condition for datatypes w.i.p * Add negative test for str.postivity check * Add some revisions * the branch is back to feet * w.i.p add lots of traces to check alg. * Add more test and revisions * Add negative and positive test to the new flag and the keyword * Fix shell tests. * Make pre-commit happy * Fix rebase conflicts * Make pre-commit happy * Add shell test, rename keyword, fix error msg * Revert change * Necessary changes * Remove wrong unless * Move the positivity checker to its own folder * Add missing juvix.yaml * Add a negative test thanks to jan * make some style changes * Make ormolu happy * Remove unnecessary instance of Show Co-authored-by: Jan Mas Rovira <janmasrovira@gmail.com>
This commit is contained in:
parent
e939f8fe9f
commit
423ccec70a
@ -12,6 +12,7 @@ data GlobalOptions = GlobalOptions
|
|||||||
_globalShowNameIds :: Bool,
|
_globalShowNameIds :: Bool,
|
||||||
_globalOnlyErrors :: Bool,
|
_globalOnlyErrors :: Bool,
|
||||||
_globalNoTermination :: Bool,
|
_globalNoTermination :: Bool,
|
||||||
|
_globalNoPositivity :: Bool,
|
||||||
_globalNoStdlib :: Bool,
|
_globalNoStdlib :: Bool,
|
||||||
_globalInputFiles :: [FilePath]
|
_globalInputFiles :: [FilePath]
|
||||||
}
|
}
|
||||||
@ -26,6 +27,7 @@ defaultGlobalOptions =
|
|||||||
_globalShowNameIds = False,
|
_globalShowNameIds = False,
|
||||||
_globalOnlyErrors = False,
|
_globalOnlyErrors = False,
|
||||||
_globalNoTermination = False,
|
_globalNoTermination = False,
|
||||||
|
_globalNoPositivity = False,
|
||||||
_globalNoStdlib = False,
|
_globalNoStdlib = False,
|
||||||
_globalInputFiles = []
|
_globalInputFiles = []
|
||||||
}
|
}
|
||||||
@ -37,6 +39,7 @@ instance Semigroup GlobalOptions where
|
|||||||
_globalShowNameIds = o1 ^. globalShowNameIds || o2 ^. globalShowNameIds,
|
_globalShowNameIds = o1 ^. globalShowNameIds || o2 ^. globalShowNameIds,
|
||||||
_globalOnlyErrors = o1 ^. globalOnlyErrors || o2 ^. globalOnlyErrors,
|
_globalOnlyErrors = o1 ^. globalOnlyErrors || o2 ^. globalOnlyErrors,
|
||||||
_globalNoTermination = o1 ^. globalNoTermination || o2 ^. globalNoTermination,
|
_globalNoTermination = o1 ^. globalNoTermination || o2 ^. globalNoTermination,
|
||||||
|
_globalNoPositivity = o1 ^. globalNoPositivity || o2 ^. globalNoPositivity,
|
||||||
_globalNoStdlib = o1 ^. globalNoStdlib || o2 ^. globalNoStdlib,
|
_globalNoStdlib = o1 ^. globalNoStdlib || o2 ^. globalNoStdlib,
|
||||||
_globalInputFiles = o1 ^. globalInputFiles ++ o2 ^. globalInputFiles
|
_globalInputFiles = o1 ^. globalInputFiles ++ o2 ^. globalInputFiles
|
||||||
}
|
}
|
||||||
@ -73,6 +76,12 @@ parseGlobalFlags b = do
|
|||||||
<> help "Disable termination checking"
|
<> help "Disable termination checking"
|
||||||
<> hidden b
|
<> hidden b
|
||||||
)
|
)
|
||||||
|
_globalNoPositivity <-
|
||||||
|
switch
|
||||||
|
( long "no-positivity"
|
||||||
|
<> help "Disable positivity checking for inductive types"
|
||||||
|
<> hidden b
|
||||||
|
)
|
||||||
_globalNoStdlib <-
|
_globalNoStdlib <-
|
||||||
switch
|
switch
|
||||||
( long "no-stdlib"
|
( long "no-stdlib"
|
||||||
|
@ -73,6 +73,7 @@ getEntryPoint r opts = nonEmpty (opts ^. globalInputFiles) >>= Just <$> entryPoi
|
|||||||
EntryPoint
|
EntryPoint
|
||||||
{ _entryPointRoot = r,
|
{ _entryPointRoot = r,
|
||||||
_entryPointNoTermination = opts ^. globalNoTermination,
|
_entryPointNoTermination = opts ^. globalNoTermination,
|
||||||
|
_entryPointNoPositivity = opts ^. globalNoPositivity,
|
||||||
_entryPointNoStdlib = opts ^. globalNoStdlib,
|
_entryPointNoStdlib = opts ^. globalNoStdlib,
|
||||||
_entryPointModulePaths = l
|
_entryPointModulePaths = l
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
- [[./notes/README.md][Notes]]
|
- [[./notes/README.md][Notes]]
|
||||||
- [[./examples/validity-predicates/README.md][Validity predicates]]
|
- [[./examples/validity-predicates/README.md][Validity predicates]]
|
||||||
- [[./notes/monomorphization.md][Monomorphization]]
|
- [[./notes/monomorphization.md][Monomorphization]]
|
||||||
|
- [[./notes/strictly-positive-data-types.md][Strictly positive data types]]
|
||||||
|
|
||||||
- [[./introduction/about/what-is.md][About]]
|
- [[./introduction/about/what-is.md][About]]
|
||||||
# - [[./introduction/about/team.md][The dev team]]
|
# - [[./introduction/about/team.md][The dev team]]
|
||||||
|
86
docs/org/notes/strictly-positive-data-types.org
Normal file
86
docs/org/notes/strictly-positive-data-types.org
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
* Strictly positive data types
|
||||||
|
|
||||||
|
We follow a syntactic description of strictly positive inductive data types.
|
||||||
|
|
||||||
|
An inductive type is said to be _strictly positive_ if it does not occur or occurs
|
||||||
|
strictly positively in the types of the arguments of its constructors. A name
|
||||||
|
qualified as strictly positive for an inductive type if it never occurs at a negative
|
||||||
|
position in the types of the arguments of its constructors. We refer to a negative
|
||||||
|
position as those occurrences on the left of an arrow in a type constructor argument.
|
||||||
|
|
||||||
|
In the example below, the type =X= occurs strictly positive in =c0= and negatively at
|
||||||
|
the constructor =c1=. Therefore, =X= is not strictly positive.
|
||||||
|
|
||||||
|
#+begin_src minijuvix
|
||||||
|
axiom B : Type;
|
||||||
|
inductive X {
|
||||||
|
c0 : (B -> X) -> X;
|
||||||
|
c1 : (X -> X) -> X;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
We could also refer to positive parameters as such parameters occurring in no negative positions.
|
||||||
|
For example, the type =B= in the =c0= constructor above is on the left of the arrow =B->X=.
|
||||||
|
Then, =B= is at a negative position. Negative parameters need to be considered when checking strictly
|
||||||
|
positive data types as they may allow to define non-strictly positive data types.
|
||||||
|
|
||||||
|
In the example below, the type =T0= is strictly positive. However, the type =T1= is not.
|
||||||
|
Only after unfolding the type application =T0 (T1 A)= in the data constructor =c1=, we can
|
||||||
|
find out that =T1= occurs at a negative position because of =T0=. More precisely,
|
||||||
|
the type parameter =A= of =T0= is negative.
|
||||||
|
|
||||||
|
#+begin_src minijuvix
|
||||||
|
inductive T0 (A : Type) {
|
||||||
|
c0 : (A -> T0 A) -> T0 A;
|
||||||
|
};
|
||||||
|
|
||||||
|
inductive T1 {
|
||||||
|
c1 : T0 T1 -> T1;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
** Bypass the strict positivity condition
|
||||||
|
|
||||||
|
To bypass the positivity check, a data type declaration can be annotated
|
||||||
|
with the keyword =positive=. Another way is to use the CLI global flag =--no-positivity=
|
||||||
|
when typechecking a =Juvix= File.
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
$ cat tests/negative/MicroJuvix/NoStrictlyPositiveDataTypes/E5.mjuvix
|
||||||
|
module E5;
|
||||||
|
positive
|
||||||
|
inductive T0 (A : Type){
|
||||||
|
c0 : (T0 A -> A) -> T0 A;
|
||||||
|
};
|
||||||
|
end;
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
** Examples of non-strictly data types
|
||||||
|
|
||||||
|
- =NSPos= is at a negative position in =c=.
|
||||||
|
#+begin_src minijuvix
|
||||||
|
inductive Empty {};
|
||||||
|
inductive NSPos {
|
||||||
|
c : ((NSPos -> Empty) -> NSPos) -> NSPos;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
- =Bad= is not strictly positive beceause of the negative parameter =A= of =Tree=.
|
||||||
|
#+begin_src minijuvix
|
||||||
|
inductive Tree (A : Type) {
|
||||||
|
leaf : Tree A;
|
||||||
|
node : (A -> Tree A) -> Tree A;
|
||||||
|
};
|
||||||
|
|
||||||
|
inductive Bad {
|
||||||
|
bad : Tree Bad -> Bad;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
- =A= is a negative parameter.
|
||||||
|
#+begin_src minijuvix
|
||||||
|
inductive B (A : Type) {
|
||||||
|
b : (A -> B (B A -> A)) -> B A;
|
||||||
|
};
|
||||||
|
#+end_src
|
140
src/Juvix/Analysis/Positivity/Checker.hs
Normal file
140
src/Juvix/Analysis/Positivity/Checker.hs
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
module Juvix.Analysis.Positivity.Checker where
|
||||||
|
|
||||||
|
import Data.HashMap.Strict qualified as HashMap
|
||||||
|
import Data.HashSet qualified as HashSet
|
||||||
|
import Juvix.Pipeline.EntryPoint qualified as E
|
||||||
|
import Juvix.Prelude hiding (fromEither)
|
||||||
|
import Juvix.Syntax.MicroJuvix.Error
|
||||||
|
import Juvix.Syntax.MicroJuvix.InfoTable
|
||||||
|
import Juvix.Syntax.MicroJuvix.Language.Extra
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Checker for strictly positive inductive data types
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type NegativeTypeParameters = HashSet VarName
|
||||||
|
|
||||||
|
type ErrorReference = Maybe Expression
|
||||||
|
|
||||||
|
type RecursionLimit = Int
|
||||||
|
|
||||||
|
checkPositivity ::
|
||||||
|
Members
|
||||||
|
'[ Reader E.EntryPoint,
|
||||||
|
Reader InfoTable,
|
||||||
|
Error TypeCheckerError,
|
||||||
|
State NegativeTypeParameters
|
||||||
|
]
|
||||||
|
r =>
|
||||||
|
InductiveDef ->
|
||||||
|
Sem r ()
|
||||||
|
checkPositivity ty = do
|
||||||
|
let indName = ty ^. inductiveName
|
||||||
|
numInductives <- HashMap.size <$> asks (^. infoInductives)
|
||||||
|
noCheckPositivity <- asks (^. E.entryPointNoPositivity)
|
||||||
|
forM_ (ty ^. inductiveConstructors) $ \ctor -> do
|
||||||
|
let ctorName = ctor ^. inductiveConstructorName
|
||||||
|
unless (noCheckPositivity || ty ^. inductivePositive) $
|
||||||
|
mapM_
|
||||||
|
(checkStrictlyPositiveOccurrences ty ctorName indName numInductives Nothing)
|
||||||
|
(ctor ^. inductiveConstructorParameters)
|
||||||
|
|
||||||
|
checkStrictlyPositiveOccurrences ::
|
||||||
|
forall r.
|
||||||
|
Members '[Reader InfoTable, Error TypeCheckerError, State NegativeTypeParameters] r =>
|
||||||
|
InductiveDef ->
|
||||||
|
ConstrName ->
|
||||||
|
Name ->
|
||||||
|
RecursionLimit ->
|
||||||
|
ErrorReference ->
|
||||||
|
Expression ->
|
||||||
|
Sem r ()
|
||||||
|
checkStrictlyPositiveOccurrences ty ctorName name recLimit ref = helper False
|
||||||
|
where
|
||||||
|
indName :: Name
|
||||||
|
indName = ty ^. inductiveName
|
||||||
|
|
||||||
|
-- The following `helper` function determines if there is any negative
|
||||||
|
-- occurence of the symbol `name` in the given expression. The `inside` flag
|
||||||
|
-- used below indicates whether the current search is performed on the left
|
||||||
|
-- of an inner arrow or not.
|
||||||
|
|
||||||
|
helper :: Bool -> Expression -> Sem r ()
|
||||||
|
helper inside expr = case expr of
|
||||||
|
ExpressionIden i -> helperIden i
|
||||||
|
ExpressionFunction (Function l r) -> helper True (l ^. paramType) >> helper inside r
|
||||||
|
ExpressionApplication tyApp -> helperApp tyApp
|
||||||
|
ExpressionLiteral {} -> return ()
|
||||||
|
ExpressionHole {} -> return ()
|
||||||
|
ExpressionUniverse {} -> return ()
|
||||||
|
where
|
||||||
|
helperIden :: Iden -> Sem r ()
|
||||||
|
helperIden = \case
|
||||||
|
IdenInductive ty' -> when (inside && name == ty') (strictlyPositivityError expr)
|
||||||
|
IdenVar name'
|
||||||
|
| not inside -> return ()
|
||||||
|
| name == name' -> strictlyPositivityError expr
|
||||||
|
| InductiveParameter name' `elem` ty ^. inductiveParameters -> modify (HashSet.insert name')
|
||||||
|
| otherwise -> return ()
|
||||||
|
_ -> return ()
|
||||||
|
|
||||||
|
helperApp :: Application -> Sem r ()
|
||||||
|
helperApp tyApp = do
|
||||||
|
let (hdExpr, args) = unfoldApplication tyApp
|
||||||
|
case hdExpr of
|
||||||
|
ExpressionIden (IdenInductive ty') -> do
|
||||||
|
when (inside && name == ty') (strictlyPositivityError expr)
|
||||||
|
InductiveInfo indTy' <- lookupInductive ty'
|
||||||
|
|
||||||
|
-- We now need to know whether `name` negatively occurs at `indTy'`
|
||||||
|
-- or not. The way to know is by checking that the type ty'
|
||||||
|
-- preserves the positivity condition, i.e., its type parameters
|
||||||
|
-- are no negative.
|
||||||
|
|
||||||
|
let paramsTy' = indTy' ^. inductiveParameters
|
||||||
|
helperInductiveApp indTy' (zip paramsTy' (toList args))
|
||||||
|
_ -> return ()
|
||||||
|
|
||||||
|
helperInductiveApp :: InductiveDef -> [(InductiveParameter, Expression)] -> Sem r ()
|
||||||
|
helperInductiveApp typ = \case
|
||||||
|
((InductiveParameter pName, arg) : ps) -> do
|
||||||
|
negParms :: NegativeTypeParameters <- get
|
||||||
|
when (varOrInductiveInExpression name arg) $ do
|
||||||
|
when (HashSet.member pName negParms) (strictlyPositivityError arg)
|
||||||
|
when (recLimit > 0) $
|
||||||
|
forM_ (typ ^. inductiveConstructors) $ \ctor' ->
|
||||||
|
mapM_
|
||||||
|
( checkStrictlyPositiveOccurrences
|
||||||
|
ty
|
||||||
|
ctorName
|
||||||
|
pName
|
||||||
|
(recLimit - 1)
|
||||||
|
(Just (fromMaybe arg ref))
|
||||||
|
)
|
||||||
|
(ctor' ^. inductiveConstructorParameters)
|
||||||
|
>> modify (HashSet.insert pName)
|
||||||
|
helperInductiveApp ty ps
|
||||||
|
[] -> return ()
|
||||||
|
|
||||||
|
strictlyPositivityError :: Expression -> Sem r ()
|
||||||
|
strictlyPositivityError expr = do
|
||||||
|
let errLoc = fromMaybe expr ref
|
||||||
|
throw
|
||||||
|
( ErrNoPositivity $
|
||||||
|
NoPositivity
|
||||||
|
{ _noStrictPositivityType = indName,
|
||||||
|
_noStrictPositivityConstructor = ctorName,
|
||||||
|
_noStrictPositivityArgument = errLoc
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
varOrInductiveInExpression :: Name -> Expression -> Bool
|
||||||
|
varOrInductiveInExpression n = \case
|
||||||
|
ExpressionIden (IdenVar var) -> n == var
|
||||||
|
ExpressionIden (IdenInductive ty) -> n == ty
|
||||||
|
ExpressionApplication (Application l r _) ->
|
||||||
|
varOrInductiveInExpression n l || varOrInductiveInExpression n r
|
||||||
|
ExpressionFunction (Function l r) ->
|
||||||
|
varOrInductiveInExpression n (l ^. paramType)
|
||||||
|
|| varOrInductiveInExpression n r
|
||||||
|
_ -> False
|
@ -182,6 +182,9 @@ cBackend = "c"
|
|||||||
terminating :: IsString s => s
|
terminating :: IsString s => s
|
||||||
terminating = "terminating"
|
terminating = "terminating"
|
||||||
|
|
||||||
|
positive :: IsString s => s
|
||||||
|
positive = "positive"
|
||||||
|
|
||||||
waveArrow :: IsString s => s
|
waveArrow :: IsString s => s
|
||||||
waveArrow = "↝"
|
waveArrow = "↝"
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import Juvix.Prelude
|
|||||||
data EntryPoint = EntryPoint
|
data EntryPoint = EntryPoint
|
||||||
{ _entryPointRoot :: FilePath,
|
{ _entryPointRoot :: FilePath,
|
||||||
_entryPointNoTermination :: Bool,
|
_entryPointNoTermination :: Bool,
|
||||||
|
_entryPointNoPositivity :: Bool,
|
||||||
_entryPointNoStdlib :: Bool,
|
_entryPointNoStdlib :: Bool,
|
||||||
_entryPointModulePaths :: NonEmpty FilePath
|
_entryPointModulePaths :: NonEmpty FilePath
|
||||||
}
|
}
|
||||||
@ -19,6 +20,7 @@ defaultEntryPoint mainFile =
|
|||||||
EntryPoint
|
EntryPoint
|
||||||
{ _entryPointRoot = ".",
|
{ _entryPointRoot = ".",
|
||||||
_entryPointNoTermination = False,
|
_entryPointNoTermination = False,
|
||||||
|
_entryPointNoPositivity = False,
|
||||||
_entryPointNoStdlib = False,
|
_entryPointNoStdlib = False,
|
||||||
_entryPointModulePaths = pure mainFile
|
_entryPointModulePaths = pure mainFile
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,8 @@ data InductiveDef = InductiveDef
|
|||||||
_inductiveBuiltin :: Maybe BuiltinInductive,
|
_inductiveBuiltin :: Maybe BuiltinInductive,
|
||||||
_inductiveParameters :: [FunctionParameter],
|
_inductiveParameters :: [FunctionParameter],
|
||||||
_inductiveType :: Expression,
|
_inductiveType :: Expression,
|
||||||
_inductiveConstructors :: [InductiveConstructorDef]
|
_inductiveConstructors :: [InductiveConstructorDef],
|
||||||
|
_inductivePositive :: Bool
|
||||||
}
|
}
|
||||||
deriving stock (Eq, Show)
|
deriving stock (Eq, Show)
|
||||||
|
|
||||||
|
@ -248,7 +248,8 @@ data InductiveDef (s :: Stage) = InductiveDef
|
|||||||
_inductiveName :: InductiveName s,
|
_inductiveName :: InductiveName s,
|
||||||
_inductiveParameters :: [InductiveParameter s],
|
_inductiveParameters :: [InductiveParameter s],
|
||||||
_inductiveType :: Maybe (ExpressionType s),
|
_inductiveType :: Maybe (ExpressionType s),
|
||||||
_inductiveConstructors :: [InductiveConstructorDef s]
|
_inductiveConstructors :: [InductiveConstructorDef s],
|
||||||
|
_inductivePositive :: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
deriving stock instance (Show (ExpressionType s), Show (SymbolType s)) => Show (InductiveDef s)
|
deriving stock instance (Show (ExpressionType s), Show (SymbolType s)) => Show (InductiveDef s)
|
||||||
|
@ -266,6 +266,9 @@ kwType = keyword Str.type_
|
|||||||
kwTerminating :: Members '[Reader ParserParams, InfoTableBuilder] r => ParsecS r ()
|
kwTerminating :: Members '[Reader ParserParams, InfoTableBuilder] r => ParsecS r ()
|
||||||
kwTerminating = keyword Str.terminating
|
kwTerminating = keyword Str.terminating
|
||||||
|
|
||||||
|
kwPositive :: Members '[Reader ParserParams, InfoTableBuilder] r => ParsecS r ()
|
||||||
|
kwPositive = keyword Str.positive
|
||||||
|
|
||||||
kwUsing :: Members '[Reader ParserParams, InfoTableBuilder] r => ParsecS r ()
|
kwUsing :: Members '[Reader ParserParams, InfoTableBuilder] r => ParsecS r ()
|
||||||
kwUsing = keyword Str.using
|
kwUsing = keyword Str.using
|
||||||
|
|
||||||
|
@ -428,6 +428,7 @@ lambda = do
|
|||||||
|
|
||||||
inductiveDef :: Members '[Reader ParserParams, InfoTableBuilder] r => Maybe BuiltinInductive -> ParsecS r (InductiveDef 'Parsed)
|
inductiveDef :: Members '[Reader ParserParams, InfoTableBuilder] r => Maybe BuiltinInductive -> ParsecS r (InductiveDef 'Parsed)
|
||||||
inductiveDef _inductiveBuiltin = do
|
inductiveDef _inductiveBuiltin = do
|
||||||
|
_inductivePositive <- isJust <$> optional kwPositive
|
||||||
kwInductive
|
kwInductive
|
||||||
_inductiveName <- symbol
|
_inductiveName <- symbol
|
||||||
_inductiveParameters <- P.many inductiveParam
|
_inductiveParameters <- P.many inductiveParam
|
||||||
|
@ -460,7 +460,7 @@ checkInductiveDef ::
|
|||||||
Members '[Error ScoperError, State Scope, State ScoperState, Reader LocalVars, InfoTableBuilder, NameIdGen] r =>
|
Members '[Error ScoperError, State Scope, State ScoperState, Reader LocalVars, InfoTableBuilder, NameIdGen] r =>
|
||||||
InductiveDef 'Parsed ->
|
InductiveDef 'Parsed ->
|
||||||
Sem r (InductiveDef 'Scoped)
|
Sem r (InductiveDef 'Scoped)
|
||||||
checkInductiveDef InductiveDef {..} = do
|
checkInductiveDef ty@InductiveDef {..} = do
|
||||||
withParams _inductiveParameters $ \inductiveParameters' -> do
|
withParams _inductiveParameters $ \inductiveParameters' -> do
|
||||||
inductiveType' <- mapM checkParseExpressionAtoms _inductiveType
|
inductiveType' <- mapM checkParseExpressionAtoms _inductiveType
|
||||||
inductiveName' <- bindInductiveSymbol _inductiveName
|
inductiveName' <- bindInductiveSymbol _inductiveName
|
||||||
@ -471,7 +471,8 @@ checkInductiveDef InductiveDef {..} = do
|
|||||||
_inductiveBuiltin = _inductiveBuiltin,
|
_inductiveBuiltin = _inductiveBuiltin,
|
||||||
_inductiveParameters = inductiveParameters',
|
_inductiveParameters = inductiveParameters',
|
||||||
_inductiveType = inductiveType',
|
_inductiveType = inductiveType',
|
||||||
_inductiveConstructors = inductiveConstructors'
|
_inductiveConstructors = inductiveConstructors',
|
||||||
|
_inductivePositive = ty ^. inductivePositive
|
||||||
}
|
}
|
||||||
|
|
||||||
checkTopModule_ ::
|
checkTopModule_ ::
|
||||||
|
@ -21,6 +21,7 @@ data TypeCheckerError
|
|||||||
| ErrTooManyArgumentsIndType WrongNumberArgumentsIndType
|
| ErrTooManyArgumentsIndType WrongNumberArgumentsIndType
|
||||||
| ErrTooFewArgumentsIndType WrongNumberArgumentsIndType
|
| ErrTooFewArgumentsIndType WrongNumberArgumentsIndType
|
||||||
| ErrImpracticalPatternMatching ImpracticalPatternMatching
|
| ErrImpracticalPatternMatching ImpracticalPatternMatching
|
||||||
|
| ErrNoPositivity NoPositivity
|
||||||
|
|
||||||
instance ToGenericError TypeCheckerError where
|
instance ToGenericError TypeCheckerError where
|
||||||
genericError :: TypeCheckerError -> GenericError
|
genericError :: TypeCheckerError -> GenericError
|
||||||
@ -34,3 +35,4 @@ instance ToGenericError TypeCheckerError where
|
|||||||
ErrTooManyArgumentsIndType e -> genericError e
|
ErrTooManyArgumentsIndType e -> genericError e
|
||||||
ErrTooFewArgumentsIndType e -> genericError e
|
ErrTooFewArgumentsIndType e -> genericError e
|
||||||
ErrImpracticalPatternMatching e -> genericError e
|
ErrImpracticalPatternMatching e -> genericError e
|
||||||
|
ErrNoPositivity e -> genericError e
|
||||||
|
@ -260,3 +260,32 @@ instance ToGenericError ImpracticalPatternMatching where
|
|||||||
<+> ppCode ty
|
<+> ppCode ty
|
||||||
<+> "is not an inductive data type."
|
<+> "is not an inductive data type."
|
||||||
<+> "Therefore, pattern-matching is not available here"
|
<+> "Therefore, pattern-matching is not available here"
|
||||||
|
|
||||||
|
data NoPositivity = NoPositivity
|
||||||
|
{ _noStrictPositivityType :: Name,
|
||||||
|
_noStrictPositivityConstructor :: Name,
|
||||||
|
_noStrictPositivityArgument :: Expression
|
||||||
|
}
|
||||||
|
|
||||||
|
makeLenses ''NoPositivity
|
||||||
|
|
||||||
|
instance ToGenericError NoPositivity where
|
||||||
|
genericError e =
|
||||||
|
GenericError
|
||||||
|
{ _genericErrorLoc = j,
|
||||||
|
_genericErrorMessage = prettyError msg,
|
||||||
|
_genericErrorIntervals = [i, j]
|
||||||
|
}
|
||||||
|
where
|
||||||
|
ty = e ^. noStrictPositivityType
|
||||||
|
ctor = e ^. noStrictPositivityConstructor
|
||||||
|
arg = e ^. noStrictPositivityArgument
|
||||||
|
i = getLoc ty
|
||||||
|
j = getLoc arg
|
||||||
|
msg =
|
||||||
|
"The type"
|
||||||
|
<+> ppCode ty
|
||||||
|
<+> "is not strictly positive."
|
||||||
|
<> line
|
||||||
|
<> "It appears at a negative position in one of the arguments of the constructor"
|
||||||
|
<+> ppCode ctor <> "."
|
||||||
|
@ -73,14 +73,14 @@ buildTable1 m = InfoTable {..} <> buildTable (map (^. includeModule) includes)
|
|||||||
_infoConstructors :: HashMap Name ConstructorInfo
|
_infoConstructors :: HashMap Name ConstructorInfo
|
||||||
_infoConstructors =
|
_infoConstructors =
|
||||||
HashMap.fromList
|
HashMap.fromList
|
||||||
[ (c ^. constructorName, ConstructorInfo params args ind builtin)
|
[ (c ^. inductiveConstructorName, ConstructorInfo params args ind builtin)
|
||||||
| StatementInductive d <- ss,
|
| StatementInductive d <- ss,
|
||||||
let ind = d ^. inductiveName,
|
let ind = d ^. inductiveName,
|
||||||
let n = length (d ^. inductiveConstructors),
|
let n = length (d ^. inductiveConstructors),
|
||||||
let params = d ^. inductiveParameters,
|
let params = d ^. inductiveParameters,
|
||||||
let builtins = maybe (replicate n Nothing) (map Just . builtinConstructors) (d ^. inductiveBuiltin),
|
let builtins = maybe (replicate n Nothing) (map Just . builtinConstructors) (d ^. inductiveBuiltin),
|
||||||
(builtin, c) <- zipExact builtins (d ^. inductiveConstructors),
|
(builtin, c) <- zipExact builtins (d ^. inductiveConstructors),
|
||||||
let args = c ^. constructorParameters
|
let args = c ^. inductiveConstructorParameters
|
||||||
]
|
]
|
||||||
_infoFunctions :: HashMap Name FunctionInfo
|
_infoFunctions :: HashMap Name FunctionInfo
|
||||||
_infoFunctions =
|
_infoFunctions =
|
||||||
@ -126,7 +126,7 @@ constructorArgTypes i =
|
|||||||
i ^. constructorInfoArgs
|
i ^. constructorInfoArgs
|
||||||
)
|
)
|
||||||
|
|
||||||
constructorType :: Member (Reader InfoTable) r => Name -> Sem r Expression
|
constructorType :: Member (Reader InfoTable) r => ConstrName -> Sem r Expression
|
||||||
constructorType c = do
|
constructorType c = do
|
||||||
info <- lookupConstructor c
|
info <- lookupConstructor c
|
||||||
let (inductiveParams, constrArgs) = constructorArgTypes info
|
let (inductiveParams, constrArgs) = constructorArgTypes info
|
||||||
|
@ -135,12 +135,14 @@ data InductiveDef = InductiveDef
|
|||||||
{ _inductiveName :: InductiveName,
|
{ _inductiveName :: InductiveName,
|
||||||
_inductiveBuiltin :: Maybe BuiltinInductive,
|
_inductiveBuiltin :: Maybe BuiltinInductive,
|
||||||
_inductiveParameters :: [InductiveParameter],
|
_inductiveParameters :: [InductiveParameter],
|
||||||
_inductiveConstructors :: [InductiveConstructorDef]
|
_inductiveConstructors :: [InductiveConstructorDef],
|
||||||
|
_inductivePositive :: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
data InductiveConstructorDef = InductiveConstructorDef
|
data InductiveConstructorDef = InductiveConstructorDef
|
||||||
{ _constructorName :: ConstrName,
|
{ _inductiveConstructorName :: ConstrName,
|
||||||
_constructorParameters :: [Expression]
|
_inductiveConstructorParameters :: [Expression],
|
||||||
|
_inductiveConstructorReturnType :: Expression
|
||||||
}
|
}
|
||||||
|
|
||||||
data FunctionParameter = FunctionParameter
|
data FunctionParameter = FunctionParameter
|
||||||
|
@ -381,10 +381,10 @@ unfoldApplication' :: Application -> (Expression, NonEmpty (IsImplicit, Expressi
|
|||||||
unfoldApplication' (Application l' r' i') = second (|: (i', r')) (unfoldExpressionApp l')
|
unfoldApplication' (Application l' r' i') = second (|: (i', r')) (unfoldExpressionApp l')
|
||||||
|
|
||||||
unfoldExpressionApp :: Expression -> (Expression, [(IsImplicit, Expression)])
|
unfoldExpressionApp :: Expression -> (Expression, [(IsImplicit, Expression)])
|
||||||
unfoldExpressionApp e = case e of
|
unfoldExpressionApp = \case
|
||||||
ExpressionApplication (Application l r i) ->
|
ExpressionApplication (Application l r i) ->
|
||||||
second (`snoc` (i, r)) (unfoldExpressionApp l)
|
second (`snoc` (i, r)) (unfoldExpressionApp l)
|
||||||
_ -> (e, [])
|
e -> (e, [])
|
||||||
|
|
||||||
unfoldApplication :: Application -> (Expression, NonEmpty Expression)
|
unfoldApplication :: Application -> (Expression, NonEmpty Expression)
|
||||||
unfoldApplication = fmap (fmap snd) . unfoldApplication'
|
unfoldApplication = fmap (fmap snd) . unfoldApplication'
|
||||||
|
@ -3,12 +3,13 @@ module Juvix.Syntax.MicroJuvix.MicroJuvixArityResult
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
import Juvix.Pipeline.EntryPoint qualified as E
|
||||||
import Juvix.Prelude
|
import Juvix.Prelude
|
||||||
import Juvix.Syntax.MicroJuvix.Language
|
import Juvix.Syntax.MicroJuvix.Language
|
||||||
import Juvix.Syntax.MicroJuvix.MicroJuvixResult (MicroJuvixResult)
|
import Juvix.Syntax.MicroJuvix.MicroJuvixResult qualified as M
|
||||||
|
|
||||||
data MicroJuvixArityResult = MicroJuvixArityResult
|
data MicroJuvixArityResult = MicroJuvixArityResult
|
||||||
{ _resultMicroJuvixResult :: MicroJuvixResult,
|
{ _resultMicroJuvixResult :: M.MicroJuvixResult,
|
||||||
_resultModules :: NonEmpty Module
|
_resultModules :: NonEmpty Module
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,3 +17,6 @@ makeLenses ''MicroJuvixArityResult
|
|||||||
|
|
||||||
mainModule :: Lens' MicroJuvixArityResult Module
|
mainModule :: Lens' MicroJuvixArityResult Module
|
||||||
mainModule = resultModules . _head
|
mainModule = resultModules . _head
|
||||||
|
|
||||||
|
microJuvixArityResultEntryPoint :: Lens' MicroJuvixArityResult E.EntryPoint
|
||||||
|
microJuvixArityResultEntryPoint = resultMicroJuvixResult . M.microJuvixResultEntryPoint
|
||||||
|
@ -4,6 +4,7 @@ module Juvix.Syntax.MicroJuvix.MicroJuvixResult
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
import Juvix.Pipeline.EntryPoint qualified as E
|
||||||
import Juvix.Prelude
|
import Juvix.Prelude
|
||||||
import Juvix.Syntax.Abstract.AbstractResult qualified as Abstract
|
import Juvix.Syntax.Abstract.AbstractResult qualified as Abstract
|
||||||
import Juvix.Syntax.MicroJuvix.InfoTable
|
import Juvix.Syntax.MicroJuvix.InfoTable
|
||||||
@ -16,3 +17,6 @@ data MicroJuvixResult = MicroJuvixResult
|
|||||||
}
|
}
|
||||||
|
|
||||||
makeLenses ''MicroJuvixResult
|
makeLenses ''MicroJuvixResult
|
||||||
|
|
||||||
|
microJuvixResultEntryPoint :: Lens' MicroJuvixResult E.EntryPoint
|
||||||
|
microJuvixResultEntryPoint = resultAbstract . Abstract.abstractResultEntryPoint
|
||||||
|
@ -154,8 +154,8 @@ instance PrettyCode Hole where
|
|||||||
|
|
||||||
instance PrettyCode InductiveConstructorDef where
|
instance PrettyCode InductiveConstructorDef where
|
||||||
ppCode c = do
|
ppCode c = do
|
||||||
constructorName' <- ppCode (c ^. constructorName)
|
constructorName' <- ppCode (c ^. inductiveConstructorName)
|
||||||
constructorParameters' <- mapM ppCodeAtom (c ^. constructorParameters)
|
constructorParameters' <- mapM ppCodeAtom (c ^. inductiveConstructorParameters)
|
||||||
return (hsep $ constructorName' : constructorParameters')
|
return (hsep $ constructorName' : constructorParameters')
|
||||||
|
|
||||||
indent' :: Member (Reader Options) r => Doc a -> Sem r (Doc a)
|
indent' :: Member (Reader Options) r => Doc a -> Sem r (Doc a)
|
||||||
|
@ -6,7 +6,9 @@ module Juvix.Syntax.MicroJuvix.TypeChecker
|
|||||||
where
|
where
|
||||||
|
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
import Data.HashMap.Strict qualified as HashMap
|
||||||
|
import Juvix.Analysis.Positivity.Checker
|
||||||
import Juvix.Internal.NameIdGen
|
import Juvix.Internal.NameIdGen
|
||||||
|
import Juvix.Pipeline.EntryPoint qualified as E
|
||||||
import Juvix.Prelude hiding (fromEither)
|
import Juvix.Prelude hiding (fromEither)
|
||||||
import Juvix.Syntax.MicroJuvix.Error
|
import Juvix.Syntax.MicroJuvix.Error
|
||||||
import Juvix.Syntax.MicroJuvix.InfoTable
|
import Juvix.Syntax.MicroJuvix.InfoTable
|
||||||
@ -21,15 +23,19 @@ addIdens idens = modify (HashMap.union idens)
|
|||||||
|
|
||||||
registerConstructor :: Members '[State TypesTable, Reader InfoTable] r => InductiveConstructorDef -> Sem r ()
|
registerConstructor :: Members '[State TypesTable, Reader InfoTable] r => InductiveConstructorDef -> Sem r ()
|
||||||
registerConstructor ctr = do
|
registerConstructor ctr = do
|
||||||
ty <- constructorType (ctr ^. constructorName)
|
ty <- constructorType (ctr ^. inductiveConstructorName)
|
||||||
modify (HashMap.insert (ctr ^. constructorName) ty)
|
modify (HashMap.insert (ctr ^. inductiveConstructorName) ty)
|
||||||
|
|
||||||
entryMicroJuvixTyped ::
|
entryMicroJuvixTyped ::
|
||||||
Members '[Error TypeCheckerError, NameIdGen] r =>
|
Members '[Error TypeCheckerError, NameIdGen] r =>
|
||||||
MicroJuvixArityResult ->
|
MicroJuvixArityResult ->
|
||||||
Sem r MicroJuvixTypedResult
|
Sem r MicroJuvixTypedResult
|
||||||
entryMicroJuvixTyped res@MicroJuvixArityResult {..} = do
|
entryMicroJuvixTyped res@MicroJuvixArityResult {..} = do
|
||||||
(idens, r) <- runState (mempty :: TypesTable) (runReader table (mapM checkModule _resultModules))
|
(idens, r) <-
|
||||||
|
runState (mempty :: TypesTable)
|
||||||
|
. runReader entryPoint
|
||||||
|
. runReader table
|
||||||
|
$ mapM checkModule _resultModules
|
||||||
return
|
return
|
||||||
MicroJuvixTypedResult
|
MicroJuvixTypedResult
|
||||||
{ _resultMicroJuvixArityResult = res,
|
{ _resultMicroJuvixArityResult = res,
|
||||||
@ -40,12 +46,16 @@ entryMicroJuvixTyped res@MicroJuvixArityResult {..} = do
|
|||||||
table :: InfoTable
|
table :: InfoTable
|
||||||
table = buildTable _resultModules
|
table = buildTable _resultModules
|
||||||
|
|
||||||
|
entryPoint :: E.EntryPoint
|
||||||
|
entryPoint = res ^. microJuvixArityResultEntryPoint
|
||||||
|
|
||||||
checkModule ::
|
checkModule ::
|
||||||
Members '[Reader InfoTable, Error TypeCheckerError, NameIdGen, State TypesTable] r =>
|
Members '[Reader E.EntryPoint, Reader InfoTable, Error TypeCheckerError, NameIdGen, State TypesTable] r =>
|
||||||
Module ->
|
Module ->
|
||||||
Sem r Module
|
Sem r Module
|
||||||
checkModule Module {..} = do
|
checkModule Module {..} = do
|
||||||
_moduleBody' <- checkModuleBody _moduleBody
|
_moduleBody' <-
|
||||||
|
(evalState (mempty :: NegativeTypeParameters) . checkModuleBody) _moduleBody
|
||||||
return
|
return
|
||||||
Module
|
Module
|
||||||
{ _moduleBody = _moduleBody',
|
{ _moduleBody = _moduleBody',
|
||||||
@ -53,7 +63,8 @@ checkModule Module {..} = do
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkModuleBody ::
|
checkModuleBody ::
|
||||||
Members '[Reader InfoTable, Error TypeCheckerError, NameIdGen, State TypesTable] r =>
|
forall r.
|
||||||
|
Members '[Reader E.EntryPoint, Reader InfoTable, Error TypeCheckerError, NameIdGen, State TypesTable, State NegativeTypeParameters] r =>
|
||||||
ModuleBody ->
|
ModuleBody ->
|
||||||
Sem r ModuleBody
|
Sem r ModuleBody
|
||||||
checkModuleBody ModuleBody {..} = do
|
checkModuleBody ModuleBody {..} = do
|
||||||
@ -64,19 +75,20 @@ checkModuleBody ModuleBody {..} = do
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkInclude ::
|
checkInclude ::
|
||||||
Members '[Reader InfoTable, Error TypeCheckerError, NameIdGen, State TypesTable] r =>
|
Members '[Reader E.EntryPoint, Reader InfoTable, Error TypeCheckerError, NameIdGen, State TypesTable] r =>
|
||||||
Include ->
|
Include ->
|
||||||
Sem r Include
|
Sem r Include
|
||||||
checkInclude = traverseOf includeModule checkModule
|
checkInclude = traverseOf includeModule checkModule
|
||||||
|
|
||||||
checkStatement ::
|
checkStatement ::
|
||||||
Members '[Reader InfoTable, Error TypeCheckerError, NameIdGen, State TypesTable] r =>
|
Members '[Reader E.EntryPoint, Reader InfoTable, Error TypeCheckerError, NameIdGen, State TypesTable, State NegativeTypeParameters] r =>
|
||||||
Statement ->
|
Statement ->
|
||||||
Sem r Statement
|
Sem r Statement
|
||||||
checkStatement s = case s of
|
checkStatement s = case s of
|
||||||
StatementFunction fun -> StatementFunction <$> checkFunctionDef fun
|
StatementFunction fun -> StatementFunction <$> checkFunctionDef fun
|
||||||
StatementForeign {} -> return s
|
StatementForeign {} -> return s
|
||||||
StatementInductive ind -> do
|
StatementInductive ind -> do
|
||||||
|
checkInductiveDef ind
|
||||||
mapM_ registerConstructor (ind ^. inductiveConstructors)
|
mapM_ registerConstructor (ind ^. inductiveConstructors)
|
||||||
ty <- inductiveType (ind ^. inductiveName)
|
ty <- inductiveType (ind ^. inductiveName)
|
||||||
modify (HashMap.insert (ind ^. inductiveName) ty)
|
modify (HashMap.insert (ind ^. inductiveName) ty)
|
||||||
@ -138,6 +150,55 @@ checkFunctionParameter (FunctionParameter mv i e) = do
|
|||||||
e' <- checkExpression (smallUniverse (getLoc e)) e
|
e' <- checkExpression (smallUniverse (getLoc e)) e
|
||||||
return (FunctionParameter mv i e')
|
return (FunctionParameter mv i e')
|
||||||
|
|
||||||
|
checkInductiveDef ::
|
||||||
|
Members '[Reader InfoTable, Error TypeCheckerError, State NegativeTypeParameters, Reader E.EntryPoint] r =>
|
||||||
|
InductiveDef ->
|
||||||
|
Sem r ()
|
||||||
|
checkInductiveDef ty@InductiveDef {..} = do
|
||||||
|
checkPositivity ty
|
||||||
|
mapM_ (checkConstructorDef ty) _inductiveConstructors
|
||||||
|
|
||||||
|
checkConstructorDef ::
|
||||||
|
Members
|
||||||
|
'[ Reader E.EntryPoint,
|
||||||
|
Reader InfoTable,
|
||||||
|
Error TypeCheckerError,
|
||||||
|
State NegativeTypeParameters
|
||||||
|
]
|
||||||
|
r =>
|
||||||
|
InductiveDef ->
|
||||||
|
InductiveConstructorDef ->
|
||||||
|
Sem r ()
|
||||||
|
checkConstructorDef ty ctor = do
|
||||||
|
checkConstructorReturnType ty ctor
|
||||||
|
|
||||||
|
checkConstructorReturnType ::
|
||||||
|
Members '[Reader InfoTable, Error TypeCheckerError] r =>
|
||||||
|
InductiveDef ->
|
||||||
|
InductiveConstructorDef ->
|
||||||
|
Sem r ()
|
||||||
|
checkConstructorReturnType indType ctor = do
|
||||||
|
let ctorName = ctor ^. inductiveConstructorName
|
||||||
|
ctorReturnType = ctor ^. inductiveConstructorReturnType
|
||||||
|
tyName = indType ^. inductiveName
|
||||||
|
indParams = map (^. inductiveParamName) (indType ^. inductiveParameters)
|
||||||
|
expectedReturnType =
|
||||||
|
foldExplicitApplication
|
||||||
|
(ExpressionIden (IdenInductive tyName))
|
||||||
|
(map (ExpressionIden . IdenVar) indParams)
|
||||||
|
when
|
||||||
|
(ctorReturnType /= expectedReturnType)
|
||||||
|
( throw
|
||||||
|
( ErrWrongReturnType
|
||||||
|
( WrongReturnType
|
||||||
|
{ _wrongReturnTypeConstructorName = ctorName,
|
||||||
|
_wrongReturnTypeExpected = expectedReturnType,
|
||||||
|
_wrongReturnTypeActual = ctorReturnType
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
inferExpression ::
|
inferExpression ::
|
||||||
Members '[Reader InfoTable, Error TypeCheckerError, NameIdGen, Reader LocalVars, Inference] r =>
|
Members '[Reader InfoTable, Error TypeCheckerError, NameIdGen, Reader LocalVars, Inference] r =>
|
||||||
Expression ->
|
Expression ->
|
||||||
|
@ -12,7 +12,7 @@ data Universe = Universe
|
|||||||
newtype SmallUniverse = SmallUniverse
|
newtype SmallUniverse = SmallUniverse
|
||||||
{ _smallUniverseLoc :: Interval
|
{ _smallUniverseLoc :: Interval
|
||||||
}
|
}
|
||||||
deriving stock (Generic)
|
deriving stock (Generic, Show)
|
||||||
|
|
||||||
instance Eq SmallUniverse where
|
instance Eq SmallUniverse where
|
||||||
_ == _ = True
|
_ == _ = True
|
||||||
|
@ -267,8 +267,6 @@ goInductiveParameter f =
|
|||||||
(Nothing, _, _) -> unsupported "unnamed inductive parameters"
|
(Nothing, _, _) -> unsupported "unnamed inductive parameters"
|
||||||
|
|
||||||
goInductiveDef ::
|
goInductiveDef ::
|
||||||
forall r.
|
|
||||||
Member (Error TypeCheckerError) r =>
|
|
||||||
Abstract.InductiveDef ->
|
Abstract.InductiveDef ->
|
||||||
Sem r InductiveDef
|
Sem r InductiveDef
|
||||||
goInductiveDef i =
|
goInductiveDef i =
|
||||||
@ -277,44 +275,28 @@ goInductiveDef i =
|
|||||||
| otherwise -> do
|
| otherwise -> do
|
||||||
inductiveParameters' <- mapM goInductiveParameter (i ^. Abstract.inductiveParameters)
|
inductiveParameters' <- mapM goInductiveParameter (i ^. Abstract.inductiveParameters)
|
||||||
let indTypeName = i ^. Abstract.inductiveName
|
let indTypeName = i ^. Abstract.inductiveName
|
||||||
indParamNames = map (^. inductiveParamName) inductiveParameters'
|
inductiveConstructors' <-
|
||||||
inductiveConstructors' <- mapM (goConstructorDef indTypeName indParamNames) (i ^. Abstract.inductiveConstructors)
|
mapM
|
||||||
|
goConstructorDef
|
||||||
|
(i ^. Abstract.inductiveConstructors)
|
||||||
return
|
return
|
||||||
InductiveDef
|
InductiveDef
|
||||||
{ _inductiveName = indTypeName,
|
{ _inductiveName = indTypeName,
|
||||||
_inductiveParameters = inductiveParameters',
|
_inductiveParameters = inductiveParameters',
|
||||||
_inductiveBuiltin = i ^. Abstract.inductiveBuiltin,
|
_inductiveBuiltin = i ^. Abstract.inductiveBuiltin,
|
||||||
_inductiveConstructors = inductiveConstructors'
|
_inductiveConstructors = inductiveConstructors',
|
||||||
|
_inductivePositive = i ^. Abstract.inductivePositive
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
goConstructorDef :: Name -> [Name] -> Abstract.InductiveConstructorDef -> Sem r InductiveConstructorDef
|
goConstructorDef :: Abstract.InductiveConstructorDef -> Sem r InductiveConstructorDef
|
||||||
goConstructorDef indName paramNames c = do
|
goConstructorDef c = do
|
||||||
(_constructorParameters', actualReturnType) <- viewConstructorType (c ^. Abstract.constructorType)
|
(cParams, cReturnType) <- viewConstructorType (c ^. Abstract.constructorType)
|
||||||
let ctorName = c ^. Abstract.constructorName
|
return
|
||||||
foldTypeAppName :: Name -> [Name] -> Expression
|
InductiveConstructorDef
|
||||||
foldTypeAppName tyName indParams =
|
{ _inductiveConstructorName = c ^. Abstract.constructorName,
|
||||||
foldExplicitApplication
|
_inductiveConstructorParameters = cParams,
|
||||||
(ExpressionIden (IdenInductive tyName))
|
_inductiveConstructorReturnType = cReturnType
|
||||||
(map (ExpressionIden . IdenVar) indParams)
|
}
|
||||||
expectedReturnType :: Expression
|
|
||||||
expectedReturnType = foldTypeAppName indName paramNames
|
|
||||||
if
|
|
||||||
| actualReturnType == expectedReturnType ->
|
|
||||||
return
|
|
||||||
InductiveConstructorDef
|
|
||||||
{ _constructorName = ctorName,
|
|
||||||
_constructorParameters = _constructorParameters'
|
|
||||||
}
|
|
||||||
| otherwise ->
|
|
||||||
throw
|
|
||||||
( ErrWrongReturnType
|
|
||||||
( WrongReturnType
|
|
||||||
{ _wrongReturnTypeConstructorName = ctorName,
|
|
||||||
_wrongReturnTypeExpected = expectedReturnType,
|
|
||||||
_wrongReturnTypeActual = actualReturnType
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
goTypeApplication :: Abstract.Application -> Sem r Application
|
goTypeApplication :: Abstract.Application -> Sem r Application
|
||||||
goTypeApplication (Abstract.Application l r i) = do
|
goTypeApplication (Abstract.Application l r i) = do
|
||||||
|
@ -485,7 +485,7 @@ mkInductiveName :: Micro.InductiveDef -> Text
|
|||||||
mkInductiveName i = mkName (i ^. Micro.inductiveName)
|
mkInductiveName i = mkName (i ^. Micro.inductiveName)
|
||||||
|
|
||||||
mkInductiveConstructorNames :: Micro.InductiveDef -> [Text]
|
mkInductiveConstructorNames :: Micro.InductiveDef -> [Text]
|
||||||
mkInductiveConstructorNames i = mkName . view Micro.constructorName <$> i ^. Micro.inductiveConstructors
|
mkInductiveConstructorNames i = mkName . view Micro.inductiveConstructorName <$> i ^. Micro.inductiveConstructors
|
||||||
|
|
||||||
mkInductiveTypeDef :: Micro.InductiveDef -> [CCode]
|
mkInductiveTypeDef :: Micro.InductiveDef -> [CCode]
|
||||||
mkInductiveTypeDef i =
|
mkInductiveTypeDef i =
|
||||||
@ -638,13 +638,13 @@ goInductiveConstructorNew i ctor = ctorNewFun
|
|||||||
ctorNewFun = if null ctorParams then return ctorNewNullary else ctorNewNary
|
ctorNewFun = if null ctorParams then return ctorNewNullary else ctorNewNary
|
||||||
|
|
||||||
baseName :: Text
|
baseName :: Text
|
||||||
baseName = mkName (ctor ^. Micro.constructorName)
|
baseName = mkName (ctor ^. Micro.inductiveConstructorName)
|
||||||
|
|
||||||
inductiveName :: Text
|
inductiveName :: Text
|
||||||
inductiveName = mkInductiveName i
|
inductiveName = mkInductiveName i
|
||||||
|
|
||||||
ctorParams :: [Micro.PolyType]
|
ctorParams :: [Micro.PolyType]
|
||||||
ctorParams = map mkPolyType' (ctor ^. Micro.constructorParameters)
|
ctorParams = map mkPolyType' (ctor ^. Micro.inductiveConstructorParameters)
|
||||||
|
|
||||||
ctorNewNullary :: [CCode]
|
ctorNewNullary :: [CCode]
|
||||||
ctorNewNullary =
|
ctorNewNullary =
|
||||||
@ -791,7 +791,7 @@ goInductiveConstructorNew i ctor = ctorNewFun
|
|||||||
)
|
)
|
||||||
|
|
||||||
inductiveCtorParams :: Members '[Reader Micro.InfoTable] r => Micro.InductiveConstructorDef -> Sem r [CDeclType]
|
inductiveCtorParams :: Members '[Reader Micro.InfoTable] r => Micro.InductiveConstructorDef -> Sem r [CDeclType]
|
||||||
inductiveCtorParams ctor = mapM (goType . mkPolyType') (ctor ^. Micro.constructorParameters)
|
inductiveCtorParams ctor = mapM (goType . mkPolyType') (ctor ^. Micro.inductiveConstructorParameters)
|
||||||
|
|
||||||
inductiveCtorArgs :: Members '[Reader Micro.InfoTable] r => Micro.InductiveConstructorDef -> Sem r [Declaration]
|
inductiveCtorArgs :: Members '[Reader Micro.InfoTable] r => Micro.InductiveConstructorDef -> Sem r [Declaration]
|
||||||
inductiveCtorArgs ctor = namedArgs asCtorArg <$> inductiveCtorParams ctor
|
inductiveCtorArgs ctor = namedArgs asCtorArg <$> inductiveCtorParams ctor
|
||||||
@ -814,10 +814,10 @@ goInductiveConstructorDef ctor = do
|
|||||||
ctorDecl = if null ctorParams then return ctorBool else ctorStruct
|
ctorDecl = if null ctorParams then return ctorBool else ctorStruct
|
||||||
|
|
||||||
baseName :: Text
|
baseName :: Text
|
||||||
baseName = mkName (ctor ^. Micro.constructorName)
|
baseName = mkName (ctor ^. Micro.inductiveConstructorName)
|
||||||
|
|
||||||
ctorParams :: [Micro.PolyType]
|
ctorParams :: [Micro.PolyType]
|
||||||
ctorParams = map mkPolyType' (ctor ^. Micro.constructorParameters)
|
ctorParams = map mkPolyType' (ctor ^. Micro.inductiveConstructorParameters)
|
||||||
|
|
||||||
ctorBool :: Declaration
|
ctorBool :: Declaration
|
||||||
ctorBool = typeDefWrap (asTypeDef baseName) BoolType
|
ctorBool = typeDefWrap (asTypeDef baseName) BoolType
|
||||||
@ -848,7 +848,7 @@ goProjections inductiveTypeDef ctor = do
|
|||||||
return (ExternalFunc <$> zipWith projFunction [0 ..] params)
|
return (ExternalFunc <$> zipWith projFunction [0 ..] params)
|
||||||
where
|
where
|
||||||
baseName :: Text
|
baseName :: Text
|
||||||
baseName = mkName (ctor ^. Micro.constructorName)
|
baseName = mkName (ctor ^. Micro.inductiveConstructorName)
|
||||||
|
|
||||||
localName :: Text
|
localName :: Text
|
||||||
localName = "a"
|
localName = "a"
|
||||||
|
@ -125,7 +125,7 @@ buildConcreteTable info =
|
|||||||
let def :: Micro.InductiveDef
|
let def :: Micro.InductiveDef
|
||||||
def = info ^?! Micro.infoInductives . at ind . _Just . Micro.inductiveInfoDef
|
def = info ^?! Micro.infoInductives . at ind . _Just . Micro.inductiveInfoDef
|
||||||
constructorNames :: [Micro.Name]
|
constructorNames :: [Micro.Name]
|
||||||
constructorNames = def ^.. Micro.inductiveConstructors . each . Micro.constructorName
|
constructorNames = def ^.. Micro.inductiveConstructors . each . Micro.inductiveConstructorName
|
||||||
k :: NonEmpty Micro.ConcreteType
|
k :: NonEmpty Micro.ConcreteType
|
||||||
k = tc ^. Micro.typeCallArguments
|
k = tc ^. Micro.typeCallArguments
|
||||||
iden :: PolyIden
|
iden :: PolyIden
|
||||||
@ -265,10 +265,10 @@ goInductiveDefConcrete def = do
|
|||||||
where
|
where
|
||||||
goConstructor :: Micro.InductiveConstructorDef -> Sem r InductiveConstructorDef
|
goConstructor :: Micro.InductiveConstructorDef -> Sem r InductiveConstructorDef
|
||||||
goConstructor c = do
|
goConstructor c = do
|
||||||
params' <- mapM (goType . Micro.mkConcreteType') (c ^. Micro.constructorParameters)
|
params' <- mapM (goType . Micro.mkConcreteType') (c ^. Micro.inductiveConstructorParameters)
|
||||||
return
|
return
|
||||||
InductiveConstructorDef
|
InductiveConstructorDef
|
||||||
{ _constructorName = c ^. Micro.constructorName,
|
{ _constructorName = c ^. Micro.inductiveConstructorName,
|
||||||
_constructorParameters = params'
|
_constructorParameters = params'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,14 +380,14 @@ goInductiveDefPoly def poly
|
|||||||
where
|
where
|
||||||
goConstructorDef :: Micro.InductiveConstructorDef -> Sem r InductiveConstructorDef
|
goConstructorDef :: Micro.InductiveConstructorDef -> Sem r InductiveConstructorDef
|
||||||
goConstructorDef cdef = do
|
goConstructorDef cdef = do
|
||||||
cpolyInfo <- fromJust <$> lookupPolyConstructor (cdef ^. Micro.constructorName)
|
cpolyInfo <- fromJust <$> lookupPolyConstructor (cdef ^. Micro.inductiveConstructorName)
|
||||||
let concrete :: ConcreteIdenInfo
|
let concrete :: ConcreteIdenInfo
|
||||||
concrete = fromJust (cpolyInfo ^. polyConcretes . at k)
|
concrete = fromJust (cpolyInfo ^. polyConcretes . at k)
|
||||||
params :: [Micro.ConcreteType]
|
params :: [Micro.ConcreteType]
|
||||||
params =
|
params =
|
||||||
map
|
map
|
||||||
(Micro.substitutionConcrete (concrete ^. concreteTypeSubs))
|
(Micro.substitutionConcrete (concrete ^. concreteTypeSubs))
|
||||||
(cdef ^. Micro.constructorParameters)
|
(cdef ^. Micro.inductiveConstructorParameters)
|
||||||
_constructorParameters <- mapM goType params
|
_constructorParameters <- mapM goType params
|
||||||
return
|
return
|
||||||
InductiveConstructorDef
|
InductiveConstructorDef
|
||||||
|
@ -57,7 +57,7 @@ goInductiveParameter :: InductiveParameter -> Sem r ()
|
|||||||
goInductiveParameter _ = return ()
|
goInductiveParameter _ = return ()
|
||||||
|
|
||||||
goInductiveConstructorDef :: Members '[State TypeCallsMap, Reader Caller, Reader InfoTable] r => InductiveConstructorDef -> Sem r ()
|
goInductiveConstructorDef :: Members '[State TypeCallsMap, Reader Caller, Reader InfoTable] r => InductiveConstructorDef -> Sem r ()
|
||||||
goInductiveConstructorDef c = mapM_ goExpression (c ^. constructorParameters)
|
goInductiveConstructorDef c = mapM_ goExpression (c ^. inductiveConstructorParameters)
|
||||||
|
|
||||||
goParam :: Members '[State TypeCallsMap, Reader Caller, Reader InfoTable] r => FunctionParameter -> Sem r ()
|
goParam :: Members '[State TypeCallsMap, Reader Caller, Reader InfoTable] r => FunctionParameter -> Sem r ()
|
||||||
goParam (FunctionParameter _ _ ty) = goExpression ty
|
goParam (FunctionParameter _ _ ty) = goExpression ty
|
||||||
|
@ -241,7 +241,7 @@ goInductive ::
|
|||||||
Members '[InfoTableBuilder, Builtins, Error ScoperError] r =>
|
Members '[InfoTableBuilder, Builtins, Error ScoperError] r =>
|
||||||
InductiveDef 'Scoped ->
|
InductiveDef 'Scoped ->
|
||||||
Sem r Abstract.InductiveDef
|
Sem r Abstract.InductiveDef
|
||||||
goInductive InductiveDef {..} = do
|
goInductive ty@InductiveDef {..} = do
|
||||||
_inductiveParameters' <- mapM goInductiveParameter _inductiveParameters
|
_inductiveParameters' <- mapM goInductiveParameter _inductiveParameters
|
||||||
_inductiveType' <- mapM goExpression _inductiveType
|
_inductiveType' <- mapM goExpression _inductiveType
|
||||||
_inductiveConstructors' <- mapM goConstructorDef _inductiveConstructors
|
_inductiveConstructors' <- mapM goConstructorDef _inductiveConstructors
|
||||||
@ -252,7 +252,8 @@ goInductive InductiveDef {..} = do
|
|||||||
_inductiveBuiltin = _inductiveBuiltin,
|
_inductiveBuiltin = _inductiveBuiltin,
|
||||||
_inductiveName = goSymbol _inductiveName,
|
_inductiveName = goSymbol _inductiveName,
|
||||||
_inductiveType = fromMaybe (Abstract.ExpressionUniverse (smallUniverse loc)) _inductiveType',
|
_inductiveType = fromMaybe (Abstract.ExpressionUniverse (smallUniverse loc)) _inductiveType',
|
||||||
_inductiveConstructors = _inductiveConstructors'
|
_inductiveConstructors = _inductiveConstructors',
|
||||||
|
_inductivePositive = ty ^. inductivePositive
|
||||||
}
|
}
|
||||||
whenJust _inductiveBuiltin (registerBuiltinInductive indDef)
|
whenJust _inductiveBuiltin (registerBuiltinInductive indDef)
|
||||||
inductiveInfo <- registerInductive indDef
|
inductiveInfo <- registerInductive indDef
|
||||||
|
@ -40,6 +40,7 @@ testDescr PosTest {..} =
|
|||||||
EntryPoint
|
EntryPoint
|
||||||
{ _entryPointRoot = cwd,
|
{ _entryPointRoot = cwd,
|
||||||
_entryPointNoTermination = False,
|
_entryPointNoTermination = False,
|
||||||
|
_entryPointNoPositivity = False,
|
||||||
_entryPointNoStdlib = noStdlib,
|
_entryPointNoStdlib = noStdlib,
|
||||||
_entryPointModulePaths = pure entryFile
|
_entryPointModulePaths = pure entryFile
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,15 @@ testDescrFlag N.NegTest {..} =
|
|||||||
{ _testName = _name,
|
{ _testName = _name,
|
||||||
_testRoot = tRoot,
|
_testRoot = tRoot,
|
||||||
_testAssertion = Single $ do
|
_testAssertion = Single $ do
|
||||||
let entryPoint = EntryPoint "." True True (pure _file)
|
let entryPoint =
|
||||||
|
EntryPoint
|
||||||
|
{ _entryPointRoot = ".",
|
||||||
|
_entryPointNoTermination = True,
|
||||||
|
_entryPointNoPositivity = False,
|
||||||
|
_entryPointNoStdlib = True,
|
||||||
|
_entryPointModulePaths = pure _file
|
||||||
|
}
|
||||||
|
|
||||||
(void . runIO) (upToMicroJuvix entryPoint)
|
(void . runIO) (upToMicroJuvix entryPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +78,7 @@ allTests =
|
|||||||
"Well-known terminating functions"
|
"Well-known terminating functions"
|
||||||
(map (mkTest . testDescr) tests),
|
(map (mkTest . testDescr) tests),
|
||||||
testGroup
|
testGroup
|
||||||
"Bypass checking using --non-termination flag on negative tests"
|
"Bypass termination checking using --non-termination flag on negative tests"
|
||||||
(map (mkTest . testDescrFlag) negTests),
|
(map (mkTest . testDescrFlag) negTests),
|
||||||
testGroup
|
testGroup
|
||||||
"Terminating keyword"
|
"Terminating keyword"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
module TypeCheck.Negative (allTests) where
|
module TypeCheck.Negative where
|
||||||
|
|
||||||
import Base
|
import Base
|
||||||
import Juvix.Pipeline
|
import Juvix.Pipeline
|
||||||
@ -31,8 +31,14 @@ testDescr NegTest {..} =
|
|||||||
allTests :: TestTree
|
allTests :: TestTree
|
||||||
allTests =
|
allTests =
|
||||||
testGroup
|
testGroup
|
||||||
"TypeCheck negative tests"
|
"Typecheck negative tests"
|
||||||
(map (mkTest . testDescr) tests)
|
[ testGroup
|
||||||
|
"General typechecking errors"
|
||||||
|
(map (mkTest . testDescr) tests),
|
||||||
|
testGroup
|
||||||
|
"Non-strictly positive data types"
|
||||||
|
(map (mkTest . testDescr) negPositivityTests)
|
||||||
|
]
|
||||||
|
|
||||||
root :: FilePath
|
root :: FilePath
|
||||||
root = "tests/negative"
|
root = "tests/negative"
|
||||||
@ -113,3 +119,43 @@ tests =
|
|||||||
ErrWrongReturnType {} -> Nothing
|
ErrWrongReturnType {} -> Nothing
|
||||||
_ -> wrongError
|
_ -> wrongError
|
||||||
]
|
]
|
||||||
|
|
||||||
|
negPositivityTests :: [NegTest]
|
||||||
|
negPositivityTests =
|
||||||
|
[ NegTest "E1" "MicroJuvix/Positivity" "E1.juvix" $
|
||||||
|
\case
|
||||||
|
ErrNoPositivity {} -> Nothing
|
||||||
|
_ -> wrongError,
|
||||||
|
NegTest "E2" "MicroJuvix/Positivity" "E2.juvix" $
|
||||||
|
\case
|
||||||
|
ErrNoPositivity {} -> Nothing
|
||||||
|
_ -> wrongError,
|
||||||
|
NegTest "E3" "MicroJuvix/Positivity" "E3.juvix" $
|
||||||
|
\case
|
||||||
|
ErrNoPositivity {} -> Nothing
|
||||||
|
_ -> wrongError,
|
||||||
|
NegTest "E4" "MicroJuvix/Positivity" "E4.juvix" $
|
||||||
|
\case
|
||||||
|
ErrNoPositivity {} -> Nothing
|
||||||
|
_ -> wrongError,
|
||||||
|
NegTest "E5" "MicroJuvix/Positivity" "E5.juvix" $
|
||||||
|
\case
|
||||||
|
ErrNoPositivity {} -> Nothing
|
||||||
|
_ -> wrongError,
|
||||||
|
NegTest "E6" "MicroJuvix/Positivity" "E6.juvix" $
|
||||||
|
\case
|
||||||
|
ErrNoPositivity {} -> Nothing
|
||||||
|
_ -> wrongError,
|
||||||
|
NegTest "E7" "MicroJuvix/Positivity" "E7.juvix" $
|
||||||
|
\case
|
||||||
|
ErrNoPositivity {} -> Nothing
|
||||||
|
_ -> wrongError,
|
||||||
|
NegTest "E8" "MicroJuvix/Positivity" "E8.juvix" $
|
||||||
|
\case
|
||||||
|
ErrNoPositivity {} -> Nothing
|
||||||
|
_ -> wrongError,
|
||||||
|
NegTest "E9" "MicroJuvix/Positivity" "E9.juvix" $
|
||||||
|
\case
|
||||||
|
ErrNoPositivity {} -> Nothing
|
||||||
|
_ -> wrongError
|
||||||
|
]
|
||||||
|
@ -2,6 +2,7 @@ module TypeCheck.Positive where
|
|||||||
|
|
||||||
import Base
|
import Base
|
||||||
import Juvix.Pipeline
|
import Juvix.Pipeline
|
||||||
|
import TypeCheck.Negative qualified as N
|
||||||
|
|
||||||
data PosTest = PosTest
|
data PosTest = PosTest
|
||||||
{ _name :: String,
|
{ _name :: String,
|
||||||
@ -23,11 +24,66 @@ testDescr PosTest {..} =
|
|||||||
(void . runIO) (upToMicroJuvixTyped entryPoint)
|
(void . runIO) (upToMicroJuvixTyped entryPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Testing --no-positivity flag with all related negative tests
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
rootNegTests :: FilePath
|
||||||
|
rootNegTests = "tests/negative/"
|
||||||
|
|
||||||
|
testNoPositivityFlag :: N.NegTest -> TestDescr
|
||||||
|
testNoPositivityFlag N.NegTest {..} =
|
||||||
|
let tRoot = rootNegTests </> _relDir
|
||||||
|
in TestDescr
|
||||||
|
{ _testName = _name,
|
||||||
|
_testRoot = tRoot,
|
||||||
|
_testAssertion = Single $ do
|
||||||
|
let entryPoint =
|
||||||
|
EntryPoint
|
||||||
|
{ _entryPointRoot = ".",
|
||||||
|
_entryPointNoTermination = False,
|
||||||
|
_entryPointNoPositivity = True,
|
||||||
|
_entryPointNoStdlib = False,
|
||||||
|
_entryPointModulePaths = pure _file
|
||||||
|
}
|
||||||
|
|
||||||
|
(void . runIO) (upToMicroJuvix entryPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
negPositivityTests :: [N.NegTest]
|
||||||
|
negPositivityTests = N.negPositivityTests
|
||||||
|
|
||||||
|
testPositivityKeyword :: [PosTest]
|
||||||
|
testPositivityKeyword =
|
||||||
|
[ PosTest
|
||||||
|
"Mark T0 data type as strictly positive"
|
||||||
|
"MicroJuvix/Positivity"
|
||||||
|
"E5.juvix"
|
||||||
|
]
|
||||||
|
|
||||||
|
positivityTestGroup :: TestTree
|
||||||
|
positivityTestGroup =
|
||||||
|
testGroup
|
||||||
|
"Positive tests for the positivity condition"
|
||||||
|
[ testGroup
|
||||||
|
"Bypass positivity checking using --non-positivity flag on negative tests"
|
||||||
|
(map (mkTest . testNoPositivityFlag) negPositivityTests),
|
||||||
|
testGroup
|
||||||
|
"Usages of the positive keyword"
|
||||||
|
(map (mkTest . testDescr) testPositivityKeyword)
|
||||||
|
]
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
allTests :: TestTree
|
allTests :: TestTree
|
||||||
allTests =
|
allTests =
|
||||||
testGroup
|
testGroup
|
||||||
"Scope positive tests"
|
"Typecheck positive tests"
|
||||||
(map (mkTest . testDescr) tests)
|
[ testGroup
|
||||||
|
"General typechecking tests"
|
||||||
|
(map (mkTest . testDescr) tests),
|
||||||
|
positivityTestGroup
|
||||||
|
]
|
||||||
|
|
||||||
tests :: [PosTest]
|
tests :: [PosTest]
|
||||||
tests =
|
tests =
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
$ juvix --help
|
$ juvix --help
|
||||||
> /Usage: juvix \(\(\-v\|\-\-version\) \| \(\-h\|\-\-help\) \| \[\-\-no\-colors\] \[\-\-show\-name\-ids\]
|
> /Usage: juvix \(\(\-v\|\-\-version\) \| \(\-h\|\-\-help\) \| \[\-\-no\-colors\] \[\-\-show\-name\-ids\]
|
||||||
\[\-\-only\-errors\] \[\-\-no\-termination\] \[\-\-no\-stdlib\] COMMAND\).*/
|
\[\-\-only\-errors\] \[\-\-no\-termination\] \[\-\-no\-positivity\]
|
||||||
|
\[\-\-no\-stdlib\] COMMAND\).*/
|
||||||
>= 0
|
>= 0
|
||||||
|
|
||||||
|
|
||||||
|
8
tests/negative/MicroJuvix/Positivity/E1.juvix
Normal file
8
tests/negative/MicroJuvix/Positivity/E1.juvix
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module E1;
|
||||||
|
|
||||||
|
axiom B : Type;
|
||||||
|
inductive X {
|
||||||
|
c : (X -> B) -> X;
|
||||||
|
};
|
||||||
|
|
||||||
|
end;
|
9
tests/negative/MicroJuvix/Positivity/E2.juvix
Normal file
9
tests/negative/MicroJuvix/Positivity/E2.juvix
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module E2;
|
||||||
|
|
||||||
|
open import NegParam;
|
||||||
|
|
||||||
|
inductive D {
|
||||||
|
d : T D -> D;
|
||||||
|
};
|
||||||
|
|
||||||
|
end;
|
8
tests/negative/MicroJuvix/Positivity/E3.juvix
Normal file
8
tests/negative/MicroJuvix/Positivity/E3.juvix
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module E3;
|
||||||
|
|
||||||
|
axiom B : Type;
|
||||||
|
inductive X {
|
||||||
|
c : B -> (X -> B) -> X;
|
||||||
|
};
|
||||||
|
|
||||||
|
end;
|
12
tests/negative/MicroJuvix/Positivity/E4.juvix
Normal file
12
tests/negative/MicroJuvix/Positivity/E4.juvix
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
module E4;
|
||||||
|
|
||||||
|
inductive Tree (A : Type) {
|
||||||
|
leaf : Tree A;
|
||||||
|
node : (A -> Tree A) -> Tree A;
|
||||||
|
};
|
||||||
|
|
||||||
|
inductive Bad {
|
||||||
|
bad : Tree Bad -> Bad;
|
||||||
|
};
|
||||||
|
|
||||||
|
end;
|
16
tests/negative/MicroJuvix/Positivity/E5.juvix
Normal file
16
tests/negative/MicroJuvix/Positivity/E5.juvix
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
module E5;
|
||||||
|
|
||||||
|
inductive T0 (A : Type){
|
||||||
|
c0 : (A -> T0 A) -> T0 A;
|
||||||
|
};
|
||||||
|
|
||||||
|
axiom B : Type;
|
||||||
|
inductive T1 (A : Type) {
|
||||||
|
c1 : (B -> T0 A) -> T1 A;
|
||||||
|
};
|
||||||
|
|
||||||
|
inductive T2 {
|
||||||
|
c2 : (B -> (B -> T1 T2)) -> T2;
|
||||||
|
};
|
||||||
|
|
||||||
|
end;
|
8
tests/negative/MicroJuvix/Positivity/E6.juvix
Normal file
8
tests/negative/MicroJuvix/Positivity/E6.juvix
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module E6;
|
||||||
|
|
||||||
|
axiom A : Type;
|
||||||
|
inductive T (A : Type) {
|
||||||
|
c : (A -> (A -> (T A -> A))) -> T A;
|
||||||
|
};
|
||||||
|
|
||||||
|
end;
|
11
tests/negative/MicroJuvix/Positivity/E7.juvix
Normal file
11
tests/negative/MicroJuvix/Positivity/E7.juvix
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module E7;
|
||||||
|
|
||||||
|
inductive T0 (A : Type) (B : Type) {
|
||||||
|
c0 : (B -> A) -> T0 A B;
|
||||||
|
};
|
||||||
|
|
||||||
|
inductive T1 (A : Type) {
|
||||||
|
c1 : (A -> T0 A (T1 A)) -> T1 A;
|
||||||
|
};
|
||||||
|
|
||||||
|
end;
|
5
tests/negative/MicroJuvix/Positivity/E8.juvix
Normal file
5
tests/negative/MicroJuvix/Positivity/E8.juvix
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module E8;
|
||||||
|
inductive B (A : Type) {
|
||||||
|
b : (A -> B (B A -> A)) -> B A;
|
||||||
|
};
|
||||||
|
end;
|
11
tests/negative/MicroJuvix/Positivity/E9.juvix
Normal file
11
tests/negative/MicroJuvix/Positivity/E9.juvix
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module E9;
|
||||||
|
|
||||||
|
inductive B {
|
||||||
|
b : B;
|
||||||
|
};
|
||||||
|
|
||||||
|
inductive T {
|
||||||
|
c : ((B → T) -> T) -> T;
|
||||||
|
};
|
||||||
|
|
||||||
|
end;
|
5
tests/negative/MicroJuvix/Positivity/NegParam.juvix
Normal file
5
tests/negative/MicroJuvix/Positivity/NegParam.juvix
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module NegParam;
|
||||||
|
inductive T (A : Type) {
|
||||||
|
c : (A -> T A) -> T A;
|
||||||
|
};
|
||||||
|
end;
|
6
tests/negative/MicroJuvix/Positivity/errorE5.test
Normal file
6
tests/negative/MicroJuvix/Positivity/errorE5.test
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
$ juvix typecheck tests/negative/MicroJuvix/Positivity/E5.juvix --no-colors
|
||||||
|
>2 /.*\.juvix\:13:21\-23\: error\:
|
||||||
|
The type T2 is not strictly positive.
|
||||||
|
It appears at a negative position in one of the arguments of the constructor c2.
|
||||||
|
/
|
||||||
|
>= 1
|
6
tests/negative/MicroJuvix/Positivity/errorE9.test
Normal file
6
tests/negative/MicroJuvix/Positivity/errorE9.test
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
$ juvix typecheck tests/negative/MicroJuvix/Positivity/E9.juvix --no-colors
|
||||||
|
>2 /.*\.juvix\:8:13\-14\: error\:
|
||||||
|
The type T is not strictly positive.
|
||||||
|
It appears at a negative position in one of the arguments of the constructor c.
|
||||||
|
/
|
||||||
|
>= 1
|
0
tests/negative/MicroJuvix/Positivity/juvix.yaml
Normal file
0
tests/negative/MicroJuvix/Positivity/juvix.yaml
Normal file
17
tests/positive/MicroJuvix/Positivity/E5.juvix
Normal file
17
tests/positive/MicroJuvix/Positivity/E5.juvix
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
module E5;
|
||||||
|
|
||||||
|
inductive T0 (A : Type){
|
||||||
|
c0 : (A -> T0 A) -> T0 A;
|
||||||
|
};
|
||||||
|
|
||||||
|
axiom B : Type;
|
||||||
|
inductive T1 (A : Type) {
|
||||||
|
c1 : (B -> T0 A) -> T1 A;
|
||||||
|
};
|
||||||
|
|
||||||
|
positive
|
||||||
|
inductive T2 {
|
||||||
|
c2 : (B -> (B -> T1 T2)) -> T2;
|
||||||
|
};
|
||||||
|
|
||||||
|
end;
|
0
tests/positive/MicroJuvix/Positivity/juvix.yaml
Normal file
0
tests/positive/MicroJuvix/Positivity/juvix.yaml
Normal file
Loading…
Reference in New Issue
Block a user