1
1
mirror of https://github.com/anoma/juvix.git synced 2024-12-01 00:04:58 +03:00

140 Support holes in type signatures (#141)

This commit is contained in:
janmasrovira 2022-06-02 13:02:07 +02:00 committed by GitHub
parent bd110723df
commit bfcaf6bde4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 108 additions and 20 deletions

View File

@ -14,8 +14,8 @@ data TypeCheckerError
| ErrWrongConstructorType WrongConstructorType
| ErrWrongConstructorAppArgs WrongConstructorAppArgs
| ErrWrongType WrongType
| ErrUnsolvedMeta UnsolvedMeta
| ErrExpectedFunctionType ExpectedFunctionType
deriving stock (Show)
instance ToGenericError TypeCheckerError where
genericError :: TypeCheckerError -> GenericError
@ -24,4 +24,5 @@ instance ToGenericError TypeCheckerError where
ErrWrongConstructorType e -> genericError e
ErrWrongConstructorAppArgs e -> genericError e
ErrWrongType e -> genericError e
ErrUnsolvedMeta e -> genericError e
ErrExpectedFunctionType e -> genericError e

View File

@ -35,6 +35,24 @@ instance ToGenericError WrongConstructorType where
<> line
<> indent' (ppCode (e ^. wrongCtorTypeExpected))
newtype UnsolvedMeta = UnsolvedMeta
{ _unsolvedMeta :: Hole
}
makeLenses ''UnsolvedMeta
instance ToGenericError UnsolvedMeta where
genericError e =
GenericError
{ _genericErrorLoc = i,
_genericErrorMessage = prettyError msg,
_genericErrorIntervals = [i]
}
where
i = getLoc (e ^. unsolvedMeta)
msg :: Doc a
msg = "Unable to infer the hole"
-- | The arguments of a constructor pattern do not match
-- the expected arguments of the constructor
data WrongConstructorAppArgs = WrongConstructorAppArgs

View File

@ -149,6 +149,17 @@ typeAsExpression = go
goFunction :: Function -> FunctionExpression
goFunction (Function l r) = FunctionExpression (go l) (go r)
fillHolesFunctionDef :: HashMap Hole Type -> FunctionDef -> FunctionDef
fillHolesFunctionDef m d =
FunctionDef
{ _funDefName = d ^. funDefName,
_funDefType = fillHolesType m (d ^. funDefType),
_funDefClauses = fmap (fillHolesClause m) (d ^. funDefClauses)
}
fillHolesClause :: HashMap Hole Type -> FunctionClause -> FunctionClause
fillHolesClause m = over clauseBody (fillHoles m)
fillHoles :: HashMap Hole Type -> Expression -> Expression
fillHoles m = goe
where

View File

@ -75,8 +75,9 @@ checkFunctionDef ::
Members '[Reader InfoTable, Error TypeCheckerError] r =>
FunctionDef ->
Sem r FunctionDef
checkFunctionDef FunctionDef {..} = do
checkFunctionDef FunctionDef {..} = runInferenceDef $ do
info <- lookupFunction _funDefName
checkFunctionDefType _funDefType
_funDefClauses' <- mapM (checkFunctionClause info) _funDefClauses
return
FunctionDef
@ -84,15 +85,34 @@ checkFunctionDef FunctionDef {..} = do
..
}
checkFunctionDefType :: forall r. Members '[Inference] r => Type -> Sem r ()
checkFunctionDefType = go
where
go :: Type -> Sem r ()
go t = case t of
TypeHole h -> void (freshMetavar h)
TypeIden {} -> return ()
TypeApp a -> goApp a
TypeFunction f -> goFunction f
TypeAbs f -> goAbs f
TypeAny -> return ()
TypeUniverse -> return ()
goApp :: TypeApplication -> Sem r ()
goApp (TypeApplication a b) = go a >> go b
goFunction :: Function -> Sem r ()
goFunction (Function a b) = go a >> go b
goAbs :: TypeAbstraction -> Sem r ()
goAbs (TypeAbstraction _ b) = go b
checkExpression ::
Members '[Reader InfoTable, Error TypeCheckerError, Reader LocalVars, Inference] r =>
Type ->
Expression ->
Sem r Expression
checkExpression t e = do
checkExpression expectedTy e = do
e' <- inferExpression' e
let inferredType = e' ^. typedType
unlessM (matchTypes t inferredType) (throw (err inferredType))
unlessM (matchTypes expectedTy inferredType) (throw (err inferredType))
return (ExpressionTyped e')
where
err infTy =
@ -100,7 +120,7 @@ checkExpression t e = do
( WrongType
{ _wrongTypeExpression = e,
_wrongTypeInferredType = infTy,
_wrongTypeExpectedType = t
_wrongTypeExpectedType = expectedTy
}
)
@ -141,16 +161,16 @@ constructorArgTypes i =
)
checkFunctionClauseBody ::
Members '[Reader InfoTable, Error TypeCheckerError] r =>
Members '[Reader InfoTable, Error TypeCheckerError, Inference] r =>
LocalVars ->
Type ->
Expression ->
Sem r Expression
checkFunctionClauseBody locals expectedTy body =
runInference (runReader locals (checkExpression expectedTy body))
runReader locals (checkExpression expectedTy body)
checkFunctionClause ::
Members '[Reader InfoTable, Error TypeCheckerError] r =>
Members '[Reader InfoTable, Error TypeCheckerError, Inference] r =>
FunctionInfo ->
FunctionClause ->
Sem r FunctionClause

View File

@ -38,7 +38,7 @@ closeState = \case
where
goHole :: Hole -> MetavarState -> Sem r' Type
goHole h = \case
Fresh -> throw @TypeCheckerError (error "unsolved meta")
Fresh -> throw (ErrUnsolvedMeta (UnsolvedMeta h))
Refined t -> do
s <- gets @(HashMap Hole Type) (^. at h)
case s of
@ -68,7 +68,7 @@ closeState = \case
getMetavar :: Member (State InferenceState) r => Hole -> Sem r MetavarState
getMetavar h = gets (fromJust . (^. inferenceMap . at h))
re :: Member (Error TypeCheckerError) r => Sem (Inference ': r) Expression -> Sem (State InferenceState ': r) Expression
re :: Member (Error TypeCheckerError) r => Sem (Inference ': r) a -> Sem (State InferenceState ': r) a
re = reinterpret $ \case
FreshMetavar h -> freshMetavar' h
MatchTypes a b -> matchTypes' a b
@ -85,21 +85,16 @@ re = reinterpret $ \case
_typedType = TypeUniverse
}
refineMetavar' ::
refineFreshMetavar ::
Members '[Error TypeCheckerError, State InferenceState] r =>
Hole ->
Type ->
Sem r ()
refineMetavar' h t = do
refineFreshMetavar h t = do
s <- gets (fromJust . (^. inferenceMap . at h))
case s of
Fresh -> modify (over inferenceMap (HashMap.insert h (Refined t)))
Refined r -> goRefine r t
goRefine :: Members '[Error TypeCheckerError, State InferenceState] r => Type -> Type -> Sem r ()
goRefine r t = do
eq <- matchTypes' r t
unless eq (error "type error: cannot match types")
Refined {} -> impossible
metavarType :: MetavarState -> Maybe Type
metavarType = \case
@ -136,7 +131,7 @@ re = reinterpret $ \case
goHole h t = do
r <- queryMetavar' h
case r of
Nothing -> refineMetavar' h t $> True
Nothing -> refineFreshMetavar h t $> True
Just ht -> matchTypes' t ht
goIden :: TypeIden -> TypeIden -> Sem r Bool
goIden ia ib = case (ia, ib) of
@ -158,3 +153,8 @@ runInference :: Member (Error TypeCheckerError) r => Sem (Inference ': r) Expres
runInference a = do
(subs, expr) <- runState iniState (re a) >>= firstM closeState
return (fillHoles subs expr)
runInferenceDef :: Member (Error TypeCheckerError) r => Sem (Inference ': r) FunctionDef -> Sem r FunctionDef
runInferenceDef a = do
(subs, expr) <- runState iniState (re a) >>= firstM closeState
return (fillHolesFunctionDef subs expr)

View File

@ -77,6 +77,13 @@ tests =
$ \case
ErrTooManyPatterns {} -> Nothing
_ -> wrongError,
NegTest
"Unsolved hole"
"MicroJuvix"
"UnsolvedMeta.mjuvix"
$ \case
ErrUnsolvedMeta {} -> Nothing
_ -> wrongError,
NegTest
"Multiple type errors are captured"
"MicroJuvix"

View File

@ -67,6 +67,10 @@ tests =
"Operators"
"."
"Operators.mjuvix",
PosTest
"Holes in type signature"
"MicroJuvix"
"HoleInSignature.mjuvix",
PosTest
"Polymorphism and higher rank functions"
"."

View File

@ -0,0 +1,10 @@
module UnsolvedMeta;
inductive Proxy (A : Type) {
x : Proxy A;
};
t : Proxy _;
t ≔ x _;
end;

View File

@ -0,0 +1,17 @@
module HoleInSignature;
inductive Pair (A : Type) (B : Type) {
mkPair : A → B → Pair A B;
};
inductive Bool {
true : Bool;
false : Bool;
};
p : Pair _ _;
p := mkPair _ _ true false;
p2 : (A : Type) → (B : Type) → _ → B → Pair A _;
p2 _ _ a b ≔ mkPair _ _ a b;
end;

View File

@ -68,7 +68,7 @@ filter _ f nil ≔ nil _;
filter _ f (cons x xs) ≔ ite _ (f x) (cons _ x (filter _ f xs)) (filter _ f xs);
map : (A : Type) → (B : Type) →
(A → B) → List A → List B;
(A → B) → List _ → List _;
map _ _ f nil ≔ nil _;
map _ _ f (cons x xs) ≔ cons _ (f x) (map _ _ f xs);