mirror of
https://github.com/anoma/juvix.git
synced 2025-01-05 14:34:03 +03:00
Fix: Add check for constructor return types (#182)
* Checking indtype declar (return type) * Add missing semicolon * Fix typo
This commit is contained in:
parent
a749575734
commit
9e817a62fa
@ -113,7 +113,7 @@ pipelineMicroJuvix ::
|
|||||||
Members '[Error MiniJuvixError] r =>
|
Members '[Error MiniJuvixError] r =>
|
||||||
Abstract.AbstractResult ->
|
Abstract.AbstractResult ->
|
||||||
Sem r MicroJuvix.MicroJuvixResult
|
Sem r MicroJuvix.MicroJuvixResult
|
||||||
pipelineMicroJuvix = mapError (MiniJuvixError @MicroJuvix.TerminationError) . MicroJuvix.entryMicroJuvix
|
pipelineMicroJuvix = MicroJuvix.entryMicroJuvix
|
||||||
|
|
||||||
pipelineMicroJuvixArity ::
|
pipelineMicroJuvixArity ::
|
||||||
Members '[Error MiniJuvixError, NameIdGen] r =>
|
Members '[Error MiniJuvixError, NameIdGen] r =>
|
||||||
|
@ -13,6 +13,7 @@ import MiniJuvix.Syntax.MicroJuvix.Error.Types
|
|||||||
|
|
||||||
data TypeCheckerError
|
data TypeCheckerError
|
||||||
= ErrWrongConstructorType WrongConstructorType
|
= ErrWrongConstructorType WrongConstructorType
|
||||||
|
| ErrWrongReturnType WrongReturnType
|
||||||
| ErrArity ArityCheckerError
|
| ErrArity ArityCheckerError
|
||||||
| ErrWrongType WrongType
|
| ErrWrongType WrongType
|
||||||
| ErrUnsolvedMeta UnsolvedMeta
|
| ErrUnsolvedMeta UnsolvedMeta
|
||||||
@ -22,6 +23,7 @@ instance ToGenericError TypeCheckerError where
|
|||||||
genericError :: TypeCheckerError -> GenericError
|
genericError :: TypeCheckerError -> GenericError
|
||||||
genericError = \case
|
genericError = \case
|
||||||
ErrWrongConstructorType e -> genericError e
|
ErrWrongConstructorType e -> genericError e
|
||||||
|
ErrWrongReturnType e -> genericError e
|
||||||
ErrArity e -> genericError e
|
ErrArity e -> genericError e
|
||||||
ErrWrongType e -> genericError e
|
ErrWrongType e -> genericError e
|
||||||
ErrUnsolvedMeta e -> genericError e
|
ErrUnsolvedMeta e -> genericError e
|
||||||
|
@ -4,6 +4,7 @@ import MiniJuvix.Prelude
|
|||||||
import MiniJuvix.Prelude.Pretty
|
import MiniJuvix.Prelude.Pretty
|
||||||
import MiniJuvix.Syntax.MicroJuvix.Error.Pretty
|
import MiniJuvix.Syntax.MicroJuvix.Error.Pretty
|
||||||
import MiniJuvix.Syntax.MicroJuvix.Language
|
import MiniJuvix.Syntax.MicroJuvix.Language
|
||||||
|
import MiniJuvix.Syntax.MicroJuvix.Language.Extra
|
||||||
|
|
||||||
-- | the type of the constructor used in a pattern does
|
-- | the type of the constructor used in a pattern does
|
||||||
-- not match the type of the inductive being matched
|
-- not match the type of the inductive being matched
|
||||||
@ -34,6 +35,34 @@ instance ToGenericError WrongConstructorType where
|
|||||||
<> line
|
<> line
|
||||||
<> indent' (ppCode (e ^. wrongCtorTypeExpected))
|
<> indent' (ppCode (e ^. wrongCtorTypeExpected))
|
||||||
|
|
||||||
|
data WrongReturnType = WrongReturnType
|
||||||
|
{ _wrongReturnTypeConstructorName :: Name,
|
||||||
|
_wrongReturnTypeExpected :: Type,
|
||||||
|
_wrongReturnTypeActual :: Type
|
||||||
|
}
|
||||||
|
|
||||||
|
makeLenses ''WrongReturnType
|
||||||
|
|
||||||
|
instance ToGenericError WrongReturnType where
|
||||||
|
genericError e =
|
||||||
|
GenericError
|
||||||
|
{ _genericErrorLoc = j,
|
||||||
|
_genericErrorMessage = prettyError msg,
|
||||||
|
_genericErrorIntervals = [i, j]
|
||||||
|
}
|
||||||
|
where
|
||||||
|
ctorName = e ^. wrongReturnTypeConstructorName
|
||||||
|
i = getLoc ctorName
|
||||||
|
j = getLoc (typeAsExpression (e ^. wrongReturnTypeActual))
|
||||||
|
msg =
|
||||||
|
"The constructor" <+> ppCode ctorName <+> "has the wrong return type:"
|
||||||
|
<> line
|
||||||
|
<> indent' (ppCode (e ^. wrongReturnTypeActual))
|
||||||
|
<> line
|
||||||
|
<> "but is expected to have type:"
|
||||||
|
<> line
|
||||||
|
<> indent' (ppCode (e ^. wrongReturnTypeExpected))
|
||||||
|
|
||||||
newtype UnsolvedMeta = UnsolvedMeta
|
newtype UnsolvedMeta = UnsolvedMeta
|
||||||
{ _unsolvedMeta :: Hole
|
{ _unsolvedMeta :: Hole
|
||||||
}
|
}
|
||||||
|
@ -411,7 +411,7 @@ foldExplicitApplication :: Expression -> [Expression] -> Expression
|
|||||||
foldExplicitApplication f = foldApplication f . zip (repeat Explicit)
|
foldExplicitApplication f = foldApplication f . zip (repeat Explicit)
|
||||||
|
|
||||||
foldApplication :: Expression -> [(IsImplicit, Expression)] -> Expression
|
foldApplication :: Expression -> [(IsImplicit, Expression)] -> Expression
|
||||||
foldApplication f args = case args of
|
foldApplication f = \case
|
||||||
[] -> f
|
[] -> f
|
||||||
((i, a) : as) -> foldApplication (ExpressionApplication (Application f a i)) as
|
((i, a) : as) -> foldApplication (ExpressionApplication (Application f a i)) as
|
||||||
|
|
||||||
@ -434,3 +434,14 @@ unfoldTypeApplication (TypeApplication l' r' _) = second (|: r') (unfoldType l')
|
|||||||
unfoldType t = case t of
|
unfoldType t = case t of
|
||||||
TypeApp (TypeApplication l r _) -> second (`snoc` r) (unfoldType l)
|
TypeApp (TypeApplication l r _) -> second (`snoc` r) (unfoldType l)
|
||||||
_ -> (t, [])
|
_ -> (t, [])
|
||||||
|
|
||||||
|
foldTypeApp :: Type -> [Type] -> Type
|
||||||
|
foldTypeApp ty = \case
|
||||||
|
[] -> ty
|
||||||
|
(p : ps) -> foldTypeApp (TypeApp (TypeApplication ty p Explicit)) ps
|
||||||
|
|
||||||
|
foldTypeAppName :: Name -> [Name] -> Type
|
||||||
|
foldTypeAppName tyName indParams =
|
||||||
|
foldTypeApp
|
||||||
|
(TypeIden (TypeIdenInductive tyName))
|
||||||
|
(map (TypeIden . TypeIdenVariable) indParams)
|
||||||
|
@ -10,7 +10,9 @@ import MiniJuvix.Pipeline.EntryPoint qualified as E
|
|||||||
import MiniJuvix.Prelude
|
import MiniJuvix.Prelude
|
||||||
import MiniJuvix.Syntax.Abstract.AbstractResult qualified as Abstract
|
import MiniJuvix.Syntax.Abstract.AbstractResult qualified as Abstract
|
||||||
import MiniJuvix.Syntax.Abstract.Language qualified as Abstract
|
import MiniJuvix.Syntax.Abstract.Language qualified as Abstract
|
||||||
|
import MiniJuvix.Syntax.MicroJuvix.Error
|
||||||
import MiniJuvix.Syntax.MicroJuvix.Language
|
import MiniJuvix.Syntax.MicroJuvix.Language
|
||||||
|
import MiniJuvix.Syntax.MicroJuvix.Language.Extra
|
||||||
import MiniJuvix.Syntax.MicroJuvix.MicroJuvixResult
|
import MiniJuvix.Syntax.MicroJuvix.MicroJuvixResult
|
||||||
import MiniJuvix.Syntax.Universe
|
import MiniJuvix.Syntax.Universe
|
||||||
import MiniJuvix.Syntax.Usage
|
import MiniJuvix.Syntax.Usage
|
||||||
@ -30,15 +32,23 @@ iniState =
|
|||||||
makeLenses ''TranslationState
|
makeLenses ''TranslationState
|
||||||
|
|
||||||
entryMicroJuvix ::
|
entryMicroJuvix ::
|
||||||
Members '[Error TerminationError] r =>
|
Members '[Error MiniJuvixError] r =>
|
||||||
Abstract.AbstractResult ->
|
Abstract.AbstractResult ->
|
||||||
Sem r MicroJuvixResult
|
Sem r MicroJuvixResult
|
||||||
entryMicroJuvix abstractResults = do
|
entryMicroJuvix abstractResults = do
|
||||||
unless noTerminationOption (checkTermination topModule infoTable)
|
unless
|
||||||
|
noTerminationOption
|
||||||
|
( mapError
|
||||||
|
(MiniJuvixError @TerminationError)
|
||||||
|
(checkTermination topModule infoTable)
|
||||||
|
)
|
||||||
_resultModules' <-
|
_resultModules' <-
|
||||||
evalState
|
evalState
|
||||||
iniState
|
iniState
|
||||||
(mapM goModule (abstractResults ^. Abstract.resultModules))
|
( mapM
|
||||||
|
(mapError (MiniJuvixError @TypeCheckerError) . goModule)
|
||||||
|
(abstractResults ^. Abstract.resultModules)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
MicroJuvixResult
|
MicroJuvixResult
|
||||||
{ _resultAbstract = abstractResults,
|
{ _resultAbstract = abstractResults,
|
||||||
@ -49,10 +59,11 @@ entryMicroJuvix abstractResults = do
|
|||||||
infoTable = abstractResults ^. Abstract.resultTable
|
infoTable = abstractResults ^. Abstract.resultTable
|
||||||
noTerminationOption =
|
noTerminationOption =
|
||||||
abstractResults
|
abstractResults
|
||||||
^. Abstract.abstractResultEntryPoint . E.entryPointNoTermination
|
^. Abstract.abstractResultEntryPoint
|
||||||
|
. E.entryPointNoTermination
|
||||||
|
|
||||||
goModule ::
|
goModule ::
|
||||||
Member (State TranslationState) r =>
|
Members '[State TranslationState, Error TypeCheckerError] r =>
|
||||||
Abstract.TopModule ->
|
Abstract.TopModule ->
|
||||||
Sem r Module
|
Sem r Module
|
||||||
goModule m = do
|
goModule m = do
|
||||||
@ -66,10 +77,10 @@ goModule m = do
|
|||||||
unsupported :: Text -> a
|
unsupported :: Text -> a
|
||||||
unsupported thing = error ("Abstract to MicroJuvix: Not yet supported: " <> thing)
|
unsupported thing = error ("Abstract to MicroJuvix: Not yet supported: " <> thing)
|
||||||
|
|
||||||
goModuleBody :: Member (State TranslationState) r => Abstract.ModuleBody -> Sem r ModuleBody
|
goModuleBody :: Members '[State TranslationState, Error TypeCheckerError] r => Abstract.ModuleBody -> Sem r ModuleBody
|
||||||
goModuleBody b = ModuleBody <$> mapMaybeM goStatement (b ^. Abstract.moduleStatements)
|
goModuleBody b = ModuleBody <$> mapMaybeM goStatement (b ^. Abstract.moduleStatements)
|
||||||
|
|
||||||
goImport :: Member (State TranslationState) r => Abstract.TopModule -> Sem r (Maybe Include)
|
goImport :: Members '[State TranslationState, Error TypeCheckerError] r => Abstract.TopModule -> Sem r (Maybe Include)
|
||||||
goImport m = do
|
goImport m = do
|
||||||
inc <- gets (HashSet.member (m ^. Abstract.moduleName) . (^. translationStateIncluded))
|
inc <- gets (HashSet.member (m ^. Abstract.moduleName) . (^. translationStateIncluded))
|
||||||
if
|
if
|
||||||
@ -85,7 +96,7 @@ goImport m = do
|
|||||||
)
|
)
|
||||||
|
|
||||||
goStatement ::
|
goStatement ::
|
||||||
Member (State TranslationState) r =>
|
Members [State TranslationState, Error TypeCheckerError] r =>
|
||||||
Abstract.Statement ->
|
Abstract.Statement ->
|
||||||
Sem r (Maybe Statement)
|
Sem r (Maybe Statement)
|
||||||
goStatement = \case
|
goStatement = \case
|
||||||
@ -97,7 +108,7 @@ goStatement = \case
|
|||||||
Abstract.StatementInductive i -> Just . StatementInductive <$> goInductiveDef i
|
Abstract.StatementInductive i -> Just . StatementInductive <$> goInductiveDef i
|
||||||
|
|
||||||
goTypeIden :: Abstract.Iden -> TypeIden
|
goTypeIden :: Abstract.Iden -> TypeIden
|
||||||
goTypeIden i = case i of
|
goTypeIden = \case
|
||||||
Abstract.IdenFunction {} -> unsupported "functions in types"
|
Abstract.IdenFunction {} -> unsupported "functions in types"
|
||||||
Abstract.IdenConstructor {} -> unsupported "constructors in types"
|
Abstract.IdenConstructor {} -> unsupported "constructors in types"
|
||||||
Abstract.IdenVar v -> TypeIdenVariable v
|
Abstract.IdenVar v -> TypeIdenVariable v
|
||||||
@ -254,31 +265,47 @@ goInductiveParameter f =
|
|||||||
(Just {}, _, _) -> unsupported "only type variables of small types are allowed"
|
(Just {}, _, _) -> unsupported "only type variables of small types are allowed"
|
||||||
(Nothing, _, _) -> unsupported "unnamed inductive parameters"
|
(Nothing, _, _) -> unsupported "unnamed inductive parameters"
|
||||||
|
|
||||||
goInductiveDef :: forall r. Abstract.InductiveDef -> Sem r InductiveDef
|
goConstructorType :: Abstract.Expression -> Sem r [Type]
|
||||||
|
goConstructorType = fmap fst . viewConstructorType
|
||||||
|
|
||||||
|
goInductiveDef ::
|
||||||
|
forall r.
|
||||||
|
Members '[Error TypeCheckerError] r =>
|
||||||
|
Abstract.InductiveDef ->
|
||||||
|
Sem r InductiveDef
|
||||||
goInductiveDef i = case i ^. Abstract.inductiveType of
|
goInductiveDef i = case i ^. Abstract.inductiveType of
|
||||||
|
Just Abstract.ExpressionUniverse {} -> helper
|
||||||
Just {} -> unsupported "inductive indices"
|
Just {} -> unsupported "inductive indices"
|
||||||
_ -> do
|
_ -> helper
|
||||||
_inductiveParameters' <- mapM goInductiveParameter (i ^. Abstract.inductiveParameters)
|
|
||||||
_inductiveConstructors' <- mapM goConstructorDef (i ^. Abstract.inductiveConstructors)
|
|
||||||
return
|
|
||||||
InductiveDef
|
|
||||||
{ _inductiveName = indName,
|
|
||||||
_inductiveParameters = _inductiveParameters',
|
|
||||||
_inductiveConstructors = _inductiveConstructors'
|
|
||||||
}
|
|
||||||
where
|
where
|
||||||
indName = i ^. Abstract.inductiveName
|
indTypeName = i ^. Abstract.inductiveName
|
||||||
goConstructorDef :: Abstract.InductiveConstructorDef -> Sem r InductiveConstructorDef
|
helper = do
|
||||||
goConstructorDef c = do
|
inductiveParameters' <- mapM goInductiveParameter (i ^. Abstract.inductiveParameters)
|
||||||
_constructorParameters' <- goConstructorType (c ^. Abstract.constructorType)
|
let indTy :: Type = foldTypeAppName indTypeName (map (^. inductiveParamName) inductiveParameters')
|
||||||
|
inductiveConstructors' <- mapM (goConstructorDef indTy) (i ^. Abstract.inductiveConstructors)
|
||||||
return
|
return
|
||||||
InductiveConstructorDef
|
InductiveDef
|
||||||
{ _constructorName = c ^. Abstract.constructorName,
|
{ _inductiveName = indTypeName,
|
||||||
_constructorParameters = _constructorParameters'
|
_inductiveParameters = inductiveParameters',
|
||||||
|
_inductiveConstructors = inductiveConstructors'
|
||||||
}
|
}
|
||||||
-- TODO check that the return type corresponds with the inductive type
|
where
|
||||||
goConstructorType :: Abstract.Expression -> Sem r [Type]
|
goConstructorDef :: Type -> Abstract.InductiveConstructorDef -> Sem r InductiveConstructorDef
|
||||||
goConstructorType = fmap fst . viewConstructorType
|
goConstructorDef expectedReturnType c = do
|
||||||
|
(_constructorParameters', actualReturnType) <- viewConstructorType (c ^. Abstract.constructorType)
|
||||||
|
let ctorName = c ^. Abstract.constructorName
|
||||||
|
if
|
||||||
|
| actualReturnType == expectedReturnType ->
|
||||||
|
return
|
||||||
|
InductiveConstructorDef
|
||||||
|
{ _constructorName = ctorName,
|
||||||
|
_constructorParameters = _constructorParameters'
|
||||||
|
}
|
||||||
|
| otherwise ->
|
||||||
|
throw
|
||||||
|
( ErrWrongReturnType
|
||||||
|
(WrongReturnType ctorName expectedReturnType actualReturnType)
|
||||||
|
)
|
||||||
|
|
||||||
goTypeApplication :: Abstract.Application -> Sem r TypeApplication
|
goTypeApplication :: Abstract.Application -> Sem r TypeApplication
|
||||||
goTypeApplication (Abstract.Application l r i) = do
|
goTypeApplication (Abstract.Application l r i) = do
|
||||||
@ -292,7 +319,7 @@ goTypeApplication (Abstract.Application l r i) = do
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewConstructorType :: Abstract.Expression -> Sem r ([Type], Type)
|
viewConstructorType :: Abstract.Expression -> Sem r ([Type], Type)
|
||||||
viewConstructorType e = case e of
|
viewConstructorType = \case
|
||||||
Abstract.ExpressionFunction f -> first toList <$> viewFunctionType f
|
Abstract.ExpressionFunction f -> first toList <$> viewFunctionType f
|
||||||
Abstract.ExpressionIden i -> return ([], TypeIden (goTypeIden i))
|
Abstract.ExpressionIden i -> return ([], TypeIden (goTypeIden i))
|
||||||
Abstract.ExpressionHole {} -> unsupported "holes in constructor type"
|
Abstract.ExpressionHole {} -> unsupported "holes in constructor type"
|
||||||
|
@ -76,5 +76,19 @@ tests =
|
|||||||
"MultiWrongType.mjuvix"
|
"MultiWrongType.mjuvix"
|
||||||
$ \case
|
$ \case
|
||||||
ErrWrongType {} -> Nothing
|
ErrWrongType {} -> Nothing
|
||||||
|
_ -> wrongError,
|
||||||
|
NegTest
|
||||||
|
"Wrong return type name for a constructor of a simple data type"
|
||||||
|
"MicroJuvix"
|
||||||
|
"WrongReturnType.mjuvix"
|
||||||
|
$ \case
|
||||||
|
ErrWrongReturnType {} -> Nothing
|
||||||
|
_ -> wrongError,
|
||||||
|
NegTest
|
||||||
|
"Wrong return type for a constructor of a data type with parameters "
|
||||||
|
"MicroJuvix"
|
||||||
|
"WrongReturnTypeParameters.mjuvix"
|
||||||
|
$ \case
|
||||||
|
ErrWrongReturnType {} -> Nothing
|
||||||
_ -> wrongError
|
_ -> wrongError
|
||||||
]
|
]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
module FunctionApplied;
|
module FunctionApplied;
|
||||||
inductive T (A : Type) {
|
inductive T (A : Type) {
|
||||||
c : A → T;
|
c : A → T A;
|
||||||
};
|
};
|
||||||
|
|
||||||
f : {A : Type} → A → T A;
|
f : {A : Type} → A → T A;
|
||||||
|
8
tests/negative/MicroJuvix/WrongReturnType.mjuvix
Normal file
8
tests/negative/MicroJuvix/WrongReturnType.mjuvix
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module WrongReturnType;
|
||||||
|
|
||||||
|
axiom B : Type;
|
||||||
|
inductive A {
|
||||||
|
c : B;
|
||||||
|
};
|
||||||
|
|
||||||
|
end;
|
@ -0,0 +1,7 @@
|
|||||||
|
module WrongReturnTypeParameters;
|
||||||
|
|
||||||
|
inductive A (B : Type) {
|
||||||
|
c : A;
|
||||||
|
};
|
||||||
|
|
||||||
|
end;
|
@ -11,8 +11,7 @@ inductive Nat {
|
|||||||
|
|
||||||
inductive List (A : Type) {
|
inductive List (A : Type) {
|
||||||
nil : List A;
|
nil : List A;
|
||||||
-- TODO check that the return type is saturated with the proper variable
|
cons : A → List A → List A;
|
||||||
cons : A → List A → Nat;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inductive Bool {
|
inductive Bool {
|
||||||
|
@ -11,8 +11,7 @@ inductive Nat {
|
|||||||
|
|
||||||
inductive List (A : Type) {
|
inductive List (A : Type) {
|
||||||
nil : List A;
|
nil : List A;
|
||||||
-- TODO check that the return type is saturated with the proper variable
|
cons : A → List A → List A;
|
||||||
cons : A → List A → Nat;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inductive Bool {
|
inductive Bool {
|
||||||
|
Loading…
Reference in New Issue
Block a user