From 8688e4b1f5b41e9d6842eae8d999acd8f633bea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Mon, 16 Jan 2017 13:59:09 +0100 Subject: [PATCH 01/13] Move Imports to its own file --- core/diag/test/Luna/Pass/FunctionResolutionSpec.hs | 1 + core/src/Luna/IR/Imports.hs | 11 +++++++++++ core/src/Luna/Pass/Inference/FunctionResolution.hs | 4 +--- 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 core/src/Luna/IR/Imports.hs diff --git a/core/diag/test/Luna/Pass/FunctionResolutionSpec.hs b/core/diag/test/Luna/Pass/FunctionResolutionSpec.hs index 356a10829d01..1e2fc52d0ee3 100644 --- a/core/diag/test/Luna/Pass/FunctionResolutionSpec.hs +++ b/core/diag/test/Luna/Pass/FunctionResolutionSpec.hs @@ -18,6 +18,7 @@ import Luna.Pass.Inference.FunctionResolution import qualified Data.Map as Map import Luna.IR.Function.Definition as Function import Luna.IR.Function +import Luna.IR.Imports import Luna.IR.Module.Definition as Module import Control.Monad.Raise diff --git a/core/src/Luna/IR/Imports.hs b/core/src/Luna/IR/Imports.hs new file mode 100644 index 000000000000..bf707e42c8a0 --- /dev/null +++ b/core/src/Luna/IR/Imports.hs @@ -0,0 +1,11 @@ +module Luna.IR.Imports where + +import Luna.Prelude +import Luna.IR.Module.Definition +import Luna.IR.Name (Name) +import Data.Map (Map) + + + +newtype Imports = Imports (Map Name Module) +makeWrapped ''Imports diff --git a/core/src/Luna/Pass/Inference/FunctionResolution.hs b/core/src/Luna/Pass/Inference/FunctionResolution.hs index 7018a19a1b1e..e0aa0c4047d6 100644 --- a/core/src/Luna/Pass/Inference/FunctionResolution.hs +++ b/core/src/Luna/Pass/Inference/FunctionResolution.hs @@ -3,6 +3,7 @@ module Luna.Pass.Inference.FunctionResolution where import Luna.Prelude hiding (String) import Luna.IR.Function.Definition as Function import Luna.IR.Function +import Luna.IR.Imports import Luna.IR.Module.Definition as Module import Luna.IR import Luna.IR.Expr.Combinators @@ -17,9 +18,6 @@ import qualified Luna.Pass as Pass -- === Definitions === -- -newtype Imports = Imports (Map Name Module) -makeWrapped ''Imports - newtype CurrentVar = CurrentVar (Expr (ENT Var (E String) Draft)) makeWrapped ''CurrentVar From 3850180d27d1a2dc25a4d8a00316b3443200f86b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Tue, 17 Jan 2017 17:03:27 +0100 Subject: [PATCH 02/13] Import accessor function initial commit --- .../test/Luna/Pass/AccessorFunctionSpec.hs | 113 ++++++++++++++++++ core/src/Luna/IR/Class/Method.hs | 3 +- core/src/Luna/IR/Function/Definition.hs | 15 ++- core/src/Luna/IR/Module/Definition.hs | 3 + 4 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 core/diag/test/Luna/Pass/AccessorFunctionSpec.hs diff --git a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs new file mode 100644 index 000000000000..5992ad9f068d --- /dev/null +++ b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs @@ -0,0 +1,113 @@ +{-# LANGUAGE PartialTypeSignatures #-} + +module Luna.Pass.AccessorFunctionSpec (spec) where + +import Luna.Pass (SubPass, Inputs, Outputs, Preserves) +import qualified Luna.Pass as Pass + +import Test.Hspec (Spec, Expectation, describe, it, shouldBe, shouldSatisfy) +import Luna.Prelude hiding (String, s, new) +import qualified Luna.Prelude as P +import Data.Maybe (isJust) +import Data.TypeDesc +import qualified Luna.IR.Repr.Vis as Vis +import Luna.IR.Expr.Combinators +import Luna.IR.Imports +import qualified Luna.IR.Module.Definition as Module +import qualified Data.Map as Map +import Luna.IR.Function hiding (args) +import Luna.IR.Function.Definition +import Luna.IR.Expr.Layout +import Luna.IR.Expr.Layout.ENT hiding (Cons) +import Luna.IR.Name (Name) +import Luna.IR.Class.Method (Method(..)) +import Luna.IR.Class.Definition +import Luna.IR +import Luna.Pass.Inference.FunctionResolution (ImportError(..), lookupSym) +import System.Log +import Control.Monad (foldM) + + + +data AccessorFunction +type instance Abstract AccessorFunction = AccessorFunction +type instance Inputs Net AccessorFunction = '[AnyExpr, AnyExprLink] +type instance Inputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Type, AnyExprLink // Type, AnyExpr // Succs] +type instance Inputs Attr AccessorFunction = '[Imports] +type instance Inputs Event AccessorFunction = '[] + +type instance Outputs Net AccessorFunction = '[AnyExpr, AnyExprLink] +type instance Outputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Succs, AnyExpr // Type] +type instance Outputs Attr AccessorFunction = '[] +type instance Outputs Event AccessorFunction = '[New // AnyExpr, New // AnyExprLink, Import // AnyExpr, Import // AnyExprLink] + +type instance Preserves AccessorFunction = '[] + +importAccessor :: _ => Expr _ -> SubPass AccessorFunction m (Either ImportError SomeExpr) +importAccessor e = match e $ \case + Acc n v -> do + v' <- source v + tl <- readLayer @Type v' + t <- source tl + match t $ \case + Cons cls _args -> do + className <- source cls + methodName <- source n + method <- importMethod className methodName + case method of + Left err -> return $ Left err + Right (ImportedMethod self body) -> do + -- replaceNode self v' + -- add Redirect layer to body from e + unifyTypes e body + unifyTypes self v' + return $ Right body + _ -> return $ Right $ generalize e + +unifyTypes :: _ => Expr _ -> Expr _ -> SubPass AccessorFunction m (Expr _) +unifyTypes e1 e2 = do + t1 <- readLayer @Type e1 >>= source + t2 <- readLayer @Type e2 >>= source + unify t1 t2 + +data ImportedMethod = ImportedMethod { self :: SomeExpr, body :: SomeExpr } + +importMethod :: _ => Expr _ -> Expr _ -> SubPass AccessorFunction m (Either ImportError ImportedMethod) +importMethod classExpr methodNameExpr = do + className <- fmap fromString (view lit <$> match' classExpr) + methodName <- fmap fromString (view lit <$> match' methodNameExpr) + imports <- readAttr @Imports + let method = (lookupClass className >=> lookupMethod methodName) imports + case method of + Left err -> return $ Left err + Right (Method self body) -> do + translator <- importTranslator body + bodyExpr <- importFunction body + return $ Right $ ImportedMethod (translator self) bodyExpr + + +lookupClass :: Name -> Imports -> Either ImportError Class +lookupClass n imps = case matchedModules of + [] -> Left SymbolNotFound + [(_, Just f)] -> Right f + matches -> Left . SymbolAmbiguous $ fst <$> matches + where modulesWithMatchInfo = (over _2 $ flip Module.lookupClass n) <$> Map.assocs (unwrap imps) + matchedModules = filter (isJust . snd) modulesWithMatchInfo + +lookupMethod :: Name -> Class -> Either ImportError Method +lookupMethod n cls = case Map.lookup n (cls ^. methods) of + Just m -> Right m + _ -> Left SymbolNotFound + +-- test :: _ => SubPass AccessorFunction _ _ +-- test = do +-- one <- integer (1::Int) +-- int <- string "Int" +-- c <- cons_ int +-- l <- link int one +-- writeLayer @Type l one +-- +-- rawAcc "succ" one + +spec :: Spec +spec = return () diff --git a/core/src/Luna/IR/Class/Method.hs b/core/src/Luna/IR/Class/Method.hs index 0f42110f4286..b00599d9aa94 100644 --- a/core/src/Luna/IR/Class/Method.hs +++ b/core/src/Luna/IR/Class/Method.hs @@ -5,9 +5,8 @@ import Luna.IR import Luna.IR.Function.Definition (CompiledFunction) import Luna.IR.Name (Name) -data Method = Method { _self :: AnyExpr +data Method = Method { _self :: SomeExpr , _body :: CompiledFunction } makeLenses ''Method - diff --git a/core/src/Luna/IR/Function/Definition.hs b/core/src/Luna/IR/Function/Definition.hs index 14b1d5948876..4d9d0c53e28b 100644 --- a/core/src/Luna/IR/Function/Definition.hs +++ b/core/src/Luna/IR/Function/Definition.hs @@ -1,5 +1,3 @@ -{-# NoMonomorphismRestriction #-} - module Luna.IR.Function.Definition where import Luna.Prelude @@ -36,9 +34,9 @@ mkTranslationVector size knownIxes = Vector.fromList reixed where translateWith :: Vector Int -> (forall t. Elem t -> Elem t) translateWith v = idx %~ Vector.unsafeIndex v -importFunction :: forall l m. (MonadIR m, MonadRef m, Editors Net '[AnyExpr, AnyExprLink] m, Emitter (Import // AnyExpr) m, Emitter (Import // AnyExprLink) m) - => CompiledFunction -> m SomeExpr -importFunction (CompiledFunction (unwrap' -> map) r) = do +importTranslator :: forall l m. (MonadIR m, MonadRef m, Editors Net '[AnyExpr, AnyExprLink] m, Emitter (Import // AnyExpr) m, Emitter (Import // AnyExprLink) m) + => CompiledFunction -> m (SomeExpr -> SomeExpr) +importTranslator (CompiledFunction (unwrap' -> map) _) = do ir <- getIR exprNet <- readNet @AnyExpr linkNet <- readNet @AnyExprLink @@ -56,4 +54,9 @@ importFunction (CompiledFunction (unwrap' -> map) r) = do forM_ importedLinks $ emit . Payload @(Import // AnyExprLink) . (, ElemTranslations exprTranslator linkTranslator) . unsafeGeneralize forM_ importedExprs $ emit . Payload @(Import // AnyExpr) . (, ElemTranslations exprTranslator linkTranslator) . unsafeGeneralize - return $ exprTranslator r + + return exprTranslator + +importFunction :: forall l m. (MonadIR m, MonadRef m, Editors Net '[AnyExpr, AnyExprLink] m, Emitter (Import // AnyExpr) m, Emitter (Import // AnyExprLink) m) + => CompiledFunction -> m SomeExpr +importFunction cf = importTranslator cf >>= \f -> return $ f (cf ^. root) diff --git a/core/src/Luna/IR/Module/Definition.hs b/core/src/Luna/IR/Module/Definition.hs index 182f42f54967..5ac235a15a1f 100644 --- a/core/src/Luna/IR/Module/Definition.hs +++ b/core/src/Luna/IR/Module/Definition.hs @@ -17,3 +17,6 @@ makeLenses ''Module lookupFunction :: Module -> Name -> Maybe CompiledFunction lookupFunction m n = Map.lookup n $ m ^. functions + +lookupClass :: Module -> Name -> Maybe Class +lookupClass m n = Map.lookup n $ m ^. classes From 6b452e03d89509272d40209794014fc466be4329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Wed, 18 Jan 2017 15:57:32 +0100 Subject: [PATCH 03/13] Pass argument as Attr, write Redirect layer --- .../test/Luna/Pass/AccessorFunctionSpec.hs | 56 +++++++++++-------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs index 5992ad9f068d..8030b479082e 100644 --- a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs +++ b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs @@ -4,6 +4,8 @@ module Luna.Pass.AccessorFunctionSpec (spec) where import Luna.Pass (SubPass, Inputs, Outputs, Preserves) import qualified Luna.Pass as Pass +import Control.Monad.Raise (tryAll) +import qualified Luna.IR.Repr.Vis as Vis import Test.Hspec (Spec, Expectation, describe, it, shouldBe, shouldSatisfy) import Luna.Prelude hiding (String, s, new) @@ -22,47 +24,56 @@ import Luna.IR.Expr.Layout.ENT hiding (Cons) import Luna.IR.Name (Name) import Luna.IR.Class.Method (Method(..)) import Luna.IR.Class.Definition +import Luna.IR.Runner import Luna.IR +import Luna.TestUtils import Luna.Pass.Inference.FunctionResolution (ImportError(..), lookupSym) import System.Log import Control.Monad (foldM) +newtype CurrentAcc = CurrentAcc (Expr Acc) + + data AccessorFunction type instance Abstract AccessorFunction = AccessorFunction type instance Inputs Net AccessorFunction = '[AnyExpr, AnyExprLink] type instance Inputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Type, AnyExprLink // Type, AnyExpr // Succs] -type instance Inputs Attr AccessorFunction = '[Imports] +type instance Inputs Attr AccessorFunction = '[CurrentAcc, Imports] type instance Inputs Event AccessorFunction = '[] type instance Outputs Net AccessorFunction = '[AnyExpr, AnyExprLink] -type instance Outputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Succs, AnyExpr // Type] +type instance Outputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Succs, AnyExpr // Type, AnyExpr // Redirect] type instance Outputs Attr AccessorFunction = '[] type instance Outputs Event AccessorFunction = '[New // AnyExpr, New // AnyExprLink, Import // AnyExpr, Import // AnyExprLink] type instance Preserves AccessorFunction = '[] -importAccessor :: _ => Expr _ -> SubPass AccessorFunction m (Either ImportError SomeExpr) -importAccessor e = match e $ \case - Acc n v -> do - v' <- source v - tl <- readLayer @Type v' - t <- source tl - match t $ \case - Cons cls _args -> do - className <- source cls - methodName <- source n - method <- importMethod className methodName - case method of - Left err -> return $ Left err - Right (ImportedMethod self body) -> do - -- replaceNode self v' - -- add Redirect layer to body from e - unifyTypes e body - unifyTypes self v' - return $ Right body - _ -> return $ Right $ generalize e +data Redirect +type instance LayerData Redirect t = SomeExpr + +importAccessor :: _ => SubPass AccessorFunction m (Either ImportError SomeExpr) +importAccessor = do + CurrentAcc acc <- readAttr + match acc $ \case + Acc n v -> do + v' <- source v + tl <- readLayer @Type v' + t <- source tl + match t $ \case + Cons cls _args -> do + className <- source cls + methodName <- source n + method <- importMethod className methodName + case method of + Left err -> return $ Left err + Right (ImportedMethod self body) -> do + replaceNode (generalize self) (generalize v') + writeLayer @Redirect (generalize body) acc + unifyTypes acc body + unifyTypes self v' + return $ Right body unifyTypes :: _ => Expr _ -> Expr _ -> SubPass AccessorFunction m (Expr _) unifyTypes e1 e2 = do @@ -85,7 +96,6 @@ importMethod classExpr methodNameExpr = do bodyExpr <- importFunction body return $ Right $ ImportedMethod (translator self) bodyExpr - lookupClass :: Name -> Imports -> Either ImportError Class lookupClass n imps = case matchedModules of [] -> Left SymbolNotFound From 2c626889ad6e67df20566b13b9480bfcaf7cede7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Wed, 18 Jan 2017 16:11:26 +0100 Subject: [PATCH 04/13] Return meaningful errors about accessors --- .../test/Luna/Pass/AccessorFunctionSpec.hs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs index 8030b479082e..a55533d6bdd4 100644 --- a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs +++ b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs @@ -53,7 +53,10 @@ type instance Preserves AccessorFunction = '[] data Redirect type instance LayerData Redirect t = SomeExpr -importAccessor :: _ => SubPass AccessorFunction m (Either ImportError SomeExpr) +data AccessorError = MethodNotFound P.String + | AmbiguousType + +importAccessor :: _ => SubPass AccessorFunction m (Maybe AccessorError) importAccessor = do CurrentAcc acc <- readAttr match acc $ \case @@ -63,17 +66,20 @@ importAccessor = do t <- source tl match t $ \case Cons cls _args -> do - className <- source cls - methodName <- source n - method <- importMethod className methodName + classNameExpr <- source cls + methodNameExpr <- source n + method <- importMethod classNameExpr methodNameExpr case method of - Left err -> return $ Left err + Left SymbolNotFound -> do + methodName <- view lit <$> match' methodNameExpr + return $ Just $ MethodNotFound methodName Right (ImportedMethod self body) -> do replaceNode (generalize self) (generalize v') writeLayer @Redirect (generalize body) acc unifyTypes acc body unifyTypes self v' - return $ Right body + return Nothing + _ -> return $ Just AmbiguousType unifyTypes :: _ => Expr _ -> Expr _ -> SubPass AccessorFunction m (Expr _) unifyTypes e1 e2 = do From c684b0df754885e3e1beaf342a47f4a93a667853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Thu, 19 Jan 2017 16:12:09 +0100 Subject: [PATCH 05/13] First failing test --- .../test/Luna/Pass/AccessorFunctionSpec.hs | 77 +++++++++++++++---- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs index a55533d6bdd4..f84c0e287e61 100644 --- a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs +++ b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs @@ -1,13 +1,15 @@ +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PartialTypeSignatures #-} +{-# LANGUAGE UndecidableInstances #-} module Luna.Pass.AccessorFunctionSpec (spec) where -import Luna.Pass (SubPass, Inputs, Outputs, Preserves) +import Luna.Pass hiding (compile) import qualified Luna.Pass as Pass -import Control.Monad.Raise (tryAll) +import Control.Monad.Raise (MonadException(..), tryAll) import qualified Luna.IR.Repr.Vis as Vis -import Test.Hspec (Spec, Expectation, describe, it, shouldBe, shouldSatisfy) +import Test.Hspec (Spec, Expectation, describe, expectationFailure, it, shouldBe, shouldSatisfy) import Luna.Prelude hiding (String, s, new) import qualified Luna.Prelude as P import Data.Maybe (isJust) @@ -20,16 +22,19 @@ import qualified Data.Map as Map import Luna.IR.Function hiding (args) import Luna.IR.Function.Definition import Luna.IR.Expr.Layout +import Luna.Pass.Sugar.TH (makePass) import Luna.IR.Expr.Layout.ENT hiding (Cons) import Luna.IR.Name (Name) import Luna.IR.Class.Method (Method(..)) import Luna.IR.Class.Definition import Luna.IR.Runner +import Luna.Pass.Sugar.Construction import Luna.IR import Luna.TestUtils import Luna.Pass.Inference.FunctionResolution (ImportError(..), lookupSym) import System.Log import Control.Monad (foldM) +import Type.Any (AnyType) @@ -39,7 +44,7 @@ newtype CurrentAcc = CurrentAcc (Expr Acc) data AccessorFunction type instance Abstract AccessorFunction = AccessorFunction type instance Inputs Net AccessorFunction = '[AnyExpr, AnyExprLink] -type instance Inputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Type, AnyExprLink // Type, AnyExpr // Succs] +type instance Inputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Type, AnyExpr // Succs] type instance Inputs Attr AccessorFunction = '[CurrentAcc, Imports] type instance Inputs Event AccessorFunction = '[] @@ -51,10 +56,11 @@ type instance Outputs Event AccessorFunction = '[New // AnyExpr, New // AnyEx type instance Preserves AccessorFunction = '[] data Redirect -type instance LayerData Redirect t = SomeExpr +type instance LayerData Redirect t = Maybe SomeExpr data AccessorError = MethodNotFound P.String | AmbiguousType + deriving (Eq, Show) importAccessor :: _ => SubPass AccessorFunction m (Maybe AccessorError) importAccessor = do @@ -75,7 +81,7 @@ importAccessor = do return $ Just $ MethodNotFound methodName Right (ImportedMethod self body) -> do replaceNode (generalize self) (generalize v') - writeLayer @Redirect (generalize body) acc + writeLayer @Redirect (Just $ generalize body) acc unifyTypes acc body unifyTypes self v' return Nothing @@ -115,15 +121,54 @@ lookupMethod n cls = case Map.lookup n (cls ^. methods) of Just m -> Right m _ -> Left SymbolNotFound --- test :: _ => SubPass AccessorFunction _ _ --- test = do --- one <- integer (1::Int) --- int <- string "Int" --- c <- cons_ int --- l <- link int one --- writeLayer @Type l one --- --- rawAcc "succ" one +test :: _ => SubPass TestPass _ _ +test = do + one <- integer (1::Int) + int <- string "Int" + c <- cons_ int + l <- unsafeGeneralize <$> link c one + writeLayer @Type l one + + rawAcc "succ" one + +testImports :: IO Imports +testImports = do + Right succ' <- runGraph $ do + self <- strVar "self" + one <- integer (1::Int) + plus <- strVar "+" + a1 <- app plus (arg self) + a2 <- app a1 (arg one) + c <- compile $ generalize a2 + return $ Method (generalize self) c + let klass = Class Map.empty $ Map.fromList [("succ", succ')] + let mod = Module.Module (Map.fromList [("Int", klass)]) Map.empty + return $ Imports $ Map.singleton "Stdlib" mod + +instance Exception e => MonadException e IO where + raise = throwM + +initRedirect :: Req m '[Editor // Layer // AnyExpr // Redirect] => Listener New (Expr l) m +initRedirect = listener $ \(t, _) -> (writeLayer @Redirect) Nothing t +makePass 'initRedirect + +runTest m = do + imps <- testImports + out <- dropLogs $ runRefCache $ evalIRBuilder' $ evalPassManager' $ do + runRegs + addExprEventListener @Redirect initRedirectPass + attachLayer 20 (getTypeDesc @Redirect) (getTypeDesc @AnyExpr) + v <- Pass.eval' m + setAttr (getTypeDesc @Imports) imps + setAttr (getTypeDesc @CurrentAcc) v + res <- Pass.eval' importAccessor + c <- Pass.eval' @AccessorFunction checkCoherence + return (res, c) + return out spec :: Spec -spec = return () +spec = describe "accessor function importer" $ do + it "imports" $ do + (res, coherence) <- runTest test + res `shouldBe` Nothing + coherence `shouldSatisfy` null From a356a9c44c0db1e5f36b3bb3c12c3c988f1722fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Fri, 20 Jan 2017 17:34:57 +0100 Subject: [PATCH 06/13] Fix incoherence in test case --- core/diag/test/Luna/Pass/AccessorFunctionSpec.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs index f84c0e287e61..dee2c1c07a65 100644 --- a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs +++ b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs @@ -125,9 +125,8 @@ test :: _ => SubPass TestPass _ _ test = do one <- integer (1::Int) int <- string "Int" - c <- cons_ int - l <- unsafeGeneralize <$> link c one - writeLayer @Type l one + c <- cons_ @Draft int + reconnectLayer @Type c one rawAcc "succ" one From 01bfa255baf6e06cde0c663f2f0d56a7a9a1ce51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Fri, 20 Jan 2017 18:54:07 +0100 Subject: [PATCH 07/13] Check that Acc node has proper Redirect value --- .../test/Luna/Pass/AccessorFunctionSpec.hs | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs index dee2c1c07a65..bca413f9e349 100644 --- a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs +++ b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs @@ -44,7 +44,7 @@ newtype CurrentAcc = CurrentAcc (Expr Acc) data AccessorFunction type instance Abstract AccessorFunction = AccessorFunction type instance Inputs Net AccessorFunction = '[AnyExpr, AnyExprLink] -type instance Inputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Type, AnyExpr // Succs] +type instance Inputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Type, AnyExpr // Succs, AnyExpr // Redirect] type instance Inputs Attr AccessorFunction = '[CurrentAcc, Imports] type instance Inputs Event AccessorFunction = '[] @@ -64,6 +64,13 @@ data AccessorError = MethodNotFound P.String importAccessor :: _ => SubPass AccessorFunction m (Maybe AccessorError) importAccessor = do + res <- importAccessor' + case res of + Left err -> return $ Just err + Right _body -> return Nothing + +importAccessor' :: _ => SubPass AccessorFunction m (Either AccessorError SomeExpr) +importAccessor' = do CurrentAcc acc <- readAttr match acc $ \case Acc n v -> do @@ -78,14 +85,14 @@ importAccessor = do case method of Left SymbolNotFound -> do methodName <- view lit <$> match' methodNameExpr - return $ Just $ MethodNotFound methodName + return $ Left $ MethodNotFound methodName Right (ImportedMethod self body) -> do replaceNode (generalize self) (generalize v') writeLayer @Redirect (Just $ generalize body) acc unifyTypes acc body unifyTypes self v' - return Nothing - _ -> return $ Just AmbiguousType + return $ Right body + _ -> return $ Left AmbiguousType unifyTypes :: _ => Expr _ -> Expr _ -> SubPass AccessorFunction m (Expr _) unifyTypes e1 e2 = do @@ -160,14 +167,16 @@ runTest m = do v <- Pass.eval' m setAttr (getTypeDesc @Imports) imps setAttr (getTypeDesc @CurrentAcc) v - res <- Pass.eval' importAccessor + res <- Pass.eval' importAccessor' c <- Pass.eval' @AccessorFunction checkCoherence - return (res, c) + redirect <- Pass.eval' @AccessorFunction $ readLayer @Redirect v + return (res, c, redirect) return out spec :: Spec spec = describe "accessor function importer" $ do it "imports" $ do - (res, coherence) <- runTest test - res `shouldBe` Nothing + (res, coherence, redirect) <- runTest test + withRight res $ \body -> do + redirect `shouldBe` Just body coherence `shouldSatisfy` null From 48e50e9756b33b976140d9bef1c6ba115a7f59d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Fri, 20 Jan 2017 19:24:28 +0100 Subject: [PATCH 08/13] Check that unify between types of Acc and imported function body is created --- .../test/Luna/Pass/AccessorFunctionSpec.hs | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs index bca413f9e349..6fb6797f3064 100644 --- a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs +++ b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs @@ -158,6 +158,16 @@ initRedirect :: Req m '[Editor // Layer // AnyExpr // Redirect] => Listener New initRedirect = listener $ \(t, _) -> (writeLayer @Redirect) Nothing t makePass 'initRedirect +unifies :: _ => SubPass AccessorFunction _ [(SomeExpr, SomeExpr)] +unifies = do + es <- exprs + maybeUnifies <- mapM (narrowAtom @Unify) es + let unifies = catMaybes maybeUnifies + forM unifies $ flip match $ \case + Unify l r -> do + t <- (,) <$> source l <*> source r + return $ over each generalize t + runTest m = do imps <- testImports out <- dropLogs $ runRefCache $ evalIRBuilder' $ evalPassManager' $ do @@ -170,13 +180,22 @@ runTest m = do res <- Pass.eval' importAccessor' c <- Pass.eval' @AccessorFunction checkCoherence redirect <- Pass.eval' @AccessorFunction $ readLayer @Redirect v - return (res, c, redirect) + unisExist <- forM res $ \body -> Pass.eval' @AccessorFunction $ do + accType <- readLayer @Type v >>= source + bodyType <- readLayer @Type body >>= source + allUnifies <- unifies + let accBodyUnify :: (SomeExpr, SomeExpr) + accBodyUnify = (generalize accType, generalize bodyType) + return $ accBodyUnify `elem` allUnifies + + return (res, c, redirect, unisExist) return out spec :: Spec spec = describe "accessor function importer" $ do it "imports" $ do - (res, coherence, redirect) <- runTest test + (res, coherence, redirect, unisExist) <- runTest test withRight res $ \body -> do redirect `shouldBe` Just body coherence `shouldSatisfy` null + withRight unisExist $ \a -> a `shouldBe` True From 3ccca6aa3df36c348965634f949b657e155d3c0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Fri, 20 Jan 2017 20:16:06 +0100 Subject: [PATCH 09/13] More exhaustive tests Check that proper unifies are created and no other exist. Check that old "self" in imported function has no successors. Check non-successful cases. --- .../test/Luna/Pass/AccessorFunctionSpec.hs | 60 +++++++++++++++---- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs index 6fb6797f3064..b708056cd6b0 100644 --- a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs +++ b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs @@ -9,7 +9,8 @@ import qualified Luna.Pass as Pass import Control.Monad.Raise (MonadException(..), tryAll) import qualified Luna.IR.Repr.Vis as Vis -import Test.Hspec (Spec, Expectation, describe, expectationFailure, it, shouldBe, shouldSatisfy) +import qualified Data.Set as Set (null) +import Test.Hspec (Spec, Expectation, describe, expectationFailure, it, shouldBe, shouldSatisfy, shouldMatchList) import Luna.Prelude hiding (String, s, new) import qualified Luna.Prelude as P import Data.Maybe (isJust) @@ -67,9 +68,9 @@ importAccessor = do res <- importAccessor' case res of Left err -> return $ Just err - Right _body -> return Nothing + Right (_self, _body) -> return Nothing -importAccessor' :: _ => SubPass AccessorFunction m (Either AccessorError SomeExpr) +importAccessor' :: _ => SubPass AccessorFunction m (Either AccessorError (SomeExpr, SomeExpr)) importAccessor' = do CurrentAcc acc <- readAttr match acc $ \case @@ -91,7 +92,7 @@ importAccessor' = do writeLayer @Redirect (Just $ generalize body) acc unifyTypes acc body unifyTypes self v' - return $ Right body + return $ Right (self, body) _ -> return $ Left AmbiguousType unifyTypes :: _ => Expr _ -> Expr _ -> SubPass AccessorFunction m (Expr _) @@ -128,8 +129,8 @@ lookupMethod n cls = case Map.lookup n (cls ^. methods) of Just m -> Right m _ -> Left SymbolNotFound -test :: _ => SubPass TestPass _ _ -test = do +testSuccess :: _ => SubPass TestPass _ _ +testSuccess = do one <- integer (1::Int) int <- string "Int" c <- cons_ @Draft int @@ -137,6 +138,22 @@ test = do rawAcc "succ" one +testUnknownMethod :: _ => SubPass TestPass _ _ +testUnknownMethod = do + one <- integer (1::Int) + int <- string "Int" + c <- cons_ @Draft int + reconnectLayer @Type c one + + rawAcc "isLetter" one + +testAmbiguousType :: _ => SubPass TestPass _ _ +testAmbiguousType = do + one <- integer (1::Int) + int <- string "Int" + + rawAcc "isLetter" one + testImports :: IO Imports testImports = do Right succ' <- runGraph $ do @@ -180,22 +197,39 @@ runTest m = do res <- Pass.eval' importAccessor' c <- Pass.eval' @AccessorFunction checkCoherence redirect <- Pass.eval' @AccessorFunction $ readLayer @Redirect v - unisExist <- forM res $ \body -> Pass.eval' @AccessorFunction $ do + allUnifies <- Pass.eval' @AccessorFunction unifies + unifiesAndSuccs <- forM res $ \(self, body) -> Pass.eval' @AccessorFunction $ do accType <- readLayer @Type v >>= source bodyType <- readLayer @Type body >>= source - allUnifies <- unifies let accBodyUnify :: (SomeExpr, SomeExpr) accBodyUnify = (generalize accType, generalize bodyType) - return $ accBodyUnify `elem` allUnifies - return (res, c, redirect, unisExist) + selfType <- readLayer @Type self >>= source + accTargetType <- match v $ \case + Acc _ target -> source target >>= readLayer @Type >>= source + let accSelfUnify :: (SomeExpr, SomeExpr) + accSelfUnify = (generalize selfType, generalize accTargetType) + selfSuccs <- readLayer @Succs self + return $ (selfSuccs, [accBodyUnify, accSelfUnify]) + + return (res, c, redirect, allUnifies, unifiesAndSuccs) return out spec :: Spec spec = describe "accessor function importer" $ do it "imports" $ do - (res, coherence, redirect, unisExist) <- runTest test - withRight res $ \body -> do + (res, coherence, redirect, allUnifies, unifiesAndSuccs) <- runTest testSuccess + withRight res $ \(_self, body) -> do redirect `shouldBe` Just body coherence `shouldSatisfy` null - withRight unisExist $ \a -> a `shouldBe` True + withRight unifiesAndSuccs $ \(selfSuccs, unifies) -> do + selfSuccs `shouldSatisfy` Set.null + unifies `shouldMatchList` allUnifies + it "does not import unknown method" $ do + (res, coherence, redirect, allUnifies, unifiesAndSuccs) <- runTest testUnknownMethod + res `shouldBe` Left (MethodNotFound "isLetter") + coherence `shouldSatisfy` null + it "does not import when type is ambiguous" $ do + (res, coherence, redirect, allUnifies, unifiesAndSuccs) <- runTest testAmbiguousType + res `shouldBe` Left AmbiguousType + coherence `shouldSatisfy` null From 51effd51c583bdc19ef4dabae008633713385c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Fri, 20 Jan 2017 20:29:36 +0100 Subject: [PATCH 10/13] Fix after merge --- core/diag/test/Luna/Pass/AccessorFunctionSpec.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs index b708056cd6b0..920348ff7f1c 100644 --- a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs +++ b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs @@ -88,7 +88,7 @@ importAccessor' = do methodName <- view lit <$> match' methodNameExpr return $ Left $ MethodNotFound methodName Right (ImportedMethod self body) -> do - replaceNode (generalize self) (generalize v') + replaceNode self v' writeLayer @Redirect (Just $ generalize body) acc unifyTypes acc body unifyTypes self v' From cdbc11b93259d8a522eb798cdb2c68999615f5f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Tue, 24 Jan 2017 11:19:32 +0100 Subject: [PATCH 11/13] Move Redirect layer to its own file --- core/diag/test/Luna/Pass/AccessorFunctionSpec.hs | 7 +------ core/src/Luna/IR/Layer/Redirect.hs | 11 +++++++++++ core/src/Luna/IR/ToRefactor.hs | 6 ++++++ 3 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 core/src/Luna/IR/Layer/Redirect.hs diff --git a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs index 920348ff7f1c..86f608fc27b8 100644 --- a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs +++ b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs @@ -23,6 +23,7 @@ import qualified Data.Map as Map import Luna.IR.Function hiding (args) import Luna.IR.Function.Definition import Luna.IR.Expr.Layout +import Luna.IR.Layer.Redirect import Luna.Pass.Sugar.TH (makePass) import Luna.IR.Expr.Layout.ENT hiding (Cons) import Luna.IR.Name (Name) @@ -56,8 +57,6 @@ type instance Outputs Event AccessorFunction = '[New // AnyExpr, New // AnyEx type instance Preserves AccessorFunction = '[] -data Redirect -type instance LayerData Redirect t = Maybe SomeExpr data AccessorError = MethodNotFound P.String | AmbiguousType @@ -171,10 +170,6 @@ testImports = do instance Exception e => MonadException e IO where raise = throwM -initRedirect :: Req m '[Editor // Layer // AnyExpr // Redirect] => Listener New (Expr l) m -initRedirect = listener $ \(t, _) -> (writeLayer @Redirect) Nothing t -makePass 'initRedirect - unifies :: _ => SubPass AccessorFunction _ [(SomeExpr, SomeExpr)] unifies = do es <- exprs diff --git a/core/src/Luna/IR/Layer/Redirect.hs b/core/src/Luna/IR/Layer/Redirect.hs new file mode 100644 index 000000000000..1fed8d310f22 --- /dev/null +++ b/core/src/Luna/IR/Layer/Redirect.hs @@ -0,0 +1,11 @@ +{-# LANGUAGE UndecidableInstances #-} + +module Luna.IR.Layer.Redirect where + +import Luna.Prelude +import Luna.IR.Layer.Class +import Luna.IR.Internal.IR + + +data Redirect +type instance LayerData Redirect t = Maybe SomeExpr diff --git a/core/src/Luna/IR/ToRefactor.hs b/core/src/Luna/IR/ToRefactor.hs index 4ca83044f6aa..6e1694ca3e7b 100644 --- a/core/src/Luna/IR/ToRefactor.hs +++ b/core/src/Luna/IR/ToRefactor.hs @@ -18,6 +18,7 @@ import Luna.IR.Layer import Luna.IR.Layer.Type import Luna.IR.Layer.Model import Luna.IR.Layer.UID +import Luna.IR.Layer.Redirect import Luna.IR.Layer.Succs import Luna.IR.Expr.Term.Named (HasName, name) import Luna.IR.Expr.Format @@ -260,6 +261,9 @@ init4 = do addExprEventListener @Type watchTypeImportPass +initRedirect :: Req m '[Editor // Layer // AnyExpr // Redirect] => Listener New (Expr l) m +initRedirect = listener $ \(t, _) -> (writeLayer @Redirect) Nothing t +makePass 'initRedirect @@ -276,6 +280,7 @@ runRegs = do init2 init3 init4 + addExprEventListener @Redirect initRedirectPass attachLayer 0 (getTypeDesc @Model) (getTypeDesc @AnyExpr) attachLayer 0 (getTypeDesc @Model) (getTypeDesc @AnyExprLink) @@ -284,6 +289,7 @@ runRegs = do attachLayer 5 (getTypeDesc @Succs) (getTypeDesc @AnyExpr) attachLayer 10 (getTypeDesc @Type) (getTypeDesc @AnyExpr) + attachLayer 10 (getTypeDesc @Redirect) (getTypeDesc @AnyExpr) From 707f50401ebeb41ab0c868ce17bbfd641df744f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Tue, 24 Jan 2017 11:52:17 +0100 Subject: [PATCH 12/13] Keep links in Redirect layer --- core/diag/test/Luna/IR/Runner.hs | 3 ++- .../test/Luna/Pass/AccessorFunctionSpec.hs | 18 ++++++++++++++---- core/diag/test/Luna/Pass/RemoveGroupedSpec.hs | 2 +- core/diag/test/Luna/TestUtils.hs | 6 ++++-- core/src/Luna/IR/Expr/Combinators.hs | 8 ++++++++ core/src/Luna/IR/Layer/Redirect.hs | 2 +- .../src/Luna/Pass/Desugaring/BlankArguments.hs | 3 ++- .../Luna/Pass/Inference/FunctionResolution.hs | 3 ++- 8 files changed, 34 insertions(+), 11 deletions(-) diff --git a/core/diag/test/Luna/IR/Runner.hs b/core/diag/test/Luna/IR/Runner.hs index b01fa5329702..0e30dc78d255 100644 --- a/core/diag/test/Luna/IR/Runner.hs +++ b/core/diag/test/Luna/IR/Runner.hs @@ -4,6 +4,7 @@ module Luna.IR.Runner where import Luna.Prelude import Luna.IR +import Luna.IR.Layer.Redirect import Luna.Pass (SubPass, Inputs, Outputs, Preserves, Events) import qualified Luna.Pass as Pass import System.Log @@ -18,7 +19,7 @@ data TestPass type instance Abstract TestPass = TestPass type instance Inputs Net TestPass = '[AnyExpr, AnyExprLink] type instance Outputs Net TestPass = '[AnyExpr, AnyExprLink] -type instance Inputs Layer TestPass = '[AnyExpr // Model, AnyExpr // UID, AnyExpr // Type, AnyExpr // Succs, AnyExprLink // UID, AnyExprLink // Model] +type instance Inputs Layer TestPass = '[AnyExpr // Model, AnyExpr // UID, AnyExpr // Type, AnyExpr // Succs, AnyExprLink // UID, AnyExprLink // Model, AnyExpr // Redirect] type instance Outputs Layer TestPass = '[AnyExpr // Model, AnyExpr // UID, AnyExpr // Type, AnyExpr // Succs, AnyExprLink // UID, AnyExprLink // Model] type instance Inputs Attr TestPass = '[] type instance Outputs Attr TestPass = '[] diff --git a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs index 86f608fc27b8..c0c0408eaeaf 100644 --- a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs +++ b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs @@ -53,7 +53,7 @@ type instance Inputs Event AccessorFunction = '[] type instance Outputs Net AccessorFunction = '[AnyExpr, AnyExprLink] type instance Outputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Succs, AnyExpr // Type, AnyExpr // Redirect] type instance Outputs Attr AccessorFunction = '[] -type instance Outputs Event AccessorFunction = '[New // AnyExpr, New // AnyExprLink, Import // AnyExpr, Import // AnyExprLink] +type instance Outputs Event AccessorFunction = '[New // AnyExpr, New // AnyExprLink, Import // AnyExpr, Import // AnyExprLink, Delete // AnyExprLink] type instance Preserves AccessorFunction = '[] @@ -88,7 +88,7 @@ importAccessor' = do return $ Left $ MethodNotFound methodName Right (ImportedMethod self body) -> do replaceNode self v' - writeLayer @Redirect (Just $ generalize body) acc + reconnectLayer' @Redirect (Just (unsafeGeneralize body :: Expr Draft)) acc unifyTypes acc body unifyTypes self v' return $ Right (self, body) @@ -180,9 +180,12 @@ unifies = do t <- (,) <$> source l <*> source r return $ over each generalize t +snapshotVis :: (MonadIR m, Vis.MonadVis m, MonadRef m) => P.String -> Pass.Pass TestPass m +snapshotVis = Vis.snapshot + runTest m = do imps <- testImports - out <- dropLogs $ runRefCache $ evalIRBuilder' $ evalPassManager' $ do + out <- withVis $ dropLogs $ runRefCache $ evalIRBuilder' $ evalPassManager' $ do runRegs addExprEventListener @Redirect initRedirectPass attachLayer 20 (getTypeDesc @Redirect) (getTypeDesc @AnyExpr) @@ -190,8 +193,15 @@ runTest m = do setAttr (getTypeDesc @Imports) imps setAttr (getTypeDesc @CurrentAcc) v res <- Pass.eval' importAccessor' + void $ Pass.eval' $ snapshotVis "import" c <- Pass.eval' @AccessorFunction checkCoherence - redirect <- Pass.eval' @AccessorFunction $ readLayer @Redirect v + (redirect :: Maybe SomeExpr) <- Pass.eval' @AccessorFunction $ do + l <- readLayer @Redirect v + case l of + Just l' -> do + src <- source l' + return $ Just $ generalize src + _ -> return Nothing allUnifies <- Pass.eval' @AccessorFunction unifies unifiesAndSuccs <- forM res $ \(self, body) -> Pass.eval' @AccessorFunction $ do accType <- readLayer @Type v >>= source diff --git a/core/diag/test/Luna/Pass/RemoveGroupedSpec.hs b/core/diag/test/Luna/Pass/RemoveGroupedSpec.hs index a4f4e7606655..a57ce91f7358 100644 --- a/core/diag/test/Luna/Pass/RemoveGroupedSpec.hs +++ b/core/diag/test/Luna/Pass/RemoveGroupedSpec.hs @@ -129,7 +129,7 @@ desugarsTo test expected = do desugared <- Pass.eval' $ removeGrouped $ generalize x void $ Pass.eval' $ snapshotVis "desugar" orphans <- Pass.eval' @RemoveGrouped $ checkUnreachableExprs [desugared] - coherence <- Pass.eval' @RemoveGrouped checkCoherence + coherence <- Pass.eval' @TestPass checkCoherence groups <- Pass.eval' noGroupedLeftBehind expected' <- Pass.eval' expected result <- Pass.eval' $ areExpressionsIsomorphic @(SubPass RemoveGrouped _) (unsafeRelayout expected') (unsafeRelayout desugared) diff --git a/core/diag/test/Luna/TestUtils.hs b/core/diag/test/Luna/TestUtils.hs index d8f54778c6b6..be2f674c292f 100644 --- a/core/diag/test/Luna/TestUtils.hs +++ b/core/diag/test/Luna/TestUtils.hs @@ -3,6 +3,7 @@ module Luna.TestUtils where import Luna.Prelude import Luna.IR import Luna.IR.Function.Argument (Arg (..)) +import Luna.IR.Layer.Redirect import Control.Monad.Trans.Maybe import Control.Monad.State as State hiding (when) import Control.Monad (guard) @@ -120,7 +121,7 @@ data CoherenceCheck = CoherenceCheck { _incoherences :: [Incoherence] makeLenses ''CoherenceCheck type MonadCoherenceCheck m = (MonadState CoherenceCheck m, CoherenceCheckCtx m) -type CoherenceCheckCtx m = (MonadRef m, Readers Net '[AnyExpr, AnyExprLink] m, Readers Layer '[AnyExpr // Model, AnyExpr // Type, AnyExpr // Succs, AnyExprLink // Model] m) +type CoherenceCheckCtx m = (MonadRef m, Readers Net '[AnyExpr, AnyExprLink] m, Readers Layer '[AnyExpr // Model, AnyExpr // Type, AnyExpr // Succs, AnyExprLink // Model, AnyExpr // Redirect] m) checkCoherence :: CoherenceCheckCtx m => m [Incoherence] @@ -172,8 +173,9 @@ checkIsSuccessor l e = do checkIsInput :: MonadCoherenceCheck m => SomeExprLink -> SomeExpr -> m () checkIsInput l e = do tp <- readLayer @Type e + redirection <- readLayer @Redirect e fs <- symbolFields e - when (tp /= l && not (elem l fs)) $ reportIncoherence $ Incoherence DanglingTarget e l + when (tp /= l && not (elem l fs) && redirection /= Just l) $ reportIncoherence $ Incoherence DanglingTarget e l checkUnreachableExprs :: (MonadRef m, Reader Layer (AnyExpr // Model) m, Reader Layer (Elem (LINK (Elem (EXPR ANY)) (Elem (EXPR ANY))) // Model) m, diff --git a/core/src/Luna/IR/Expr/Combinators.hs b/core/src/Luna/IR/Expr/Combinators.hs index 647602b613d5..c97bead05971 100644 --- a/core/src/Luna/IR/Expr/Combinators.hs +++ b/core/src/Luna/IR/Expr/Combinators.hs @@ -70,3 +70,11 @@ reconnectLayer src tgt = do delete old link <- link (generalize src) tgt writeLayer @l link tgt + +reconnectLayer' :: forall l m a b b' t. (MonadRef m, Editors Net '[AnyExprLink] m, Editors Layer '[AnyExpr // l] m, Emitters '[Delete // AnyExprLink, New // AnyExprLink] m, Traversable t, LayerData l (Expr a) ~ t (ExprLink b a), Generalizable' (Expr b') (Expr b)) + => t (Expr b') -> Expr a -> m () +reconnectLayer' srcs tgt = do + old <- readLayer @l tgt + mapM delete old + links <- forM srcs $ \src -> link (generalize src) tgt + writeLayer @l links tgt diff --git a/core/src/Luna/IR/Layer/Redirect.hs b/core/src/Luna/IR/Layer/Redirect.hs index 1fed8d310f22..4d7694867416 100644 --- a/core/src/Luna/IR/Layer/Redirect.hs +++ b/core/src/Luna/IR/Layer/Redirect.hs @@ -8,4 +8,4 @@ import Luna.IR.Internal.IR data Redirect -type instance LayerData Redirect t = Maybe SomeExpr +type instance LayerData Redirect t = Maybe (SubLink AnyExpr t) diff --git a/core/src/Luna/Pass/Desugaring/BlankArguments.hs b/core/src/Luna/Pass/Desugaring/BlankArguments.hs index a40957beea44..e7089cf73a9b 100644 --- a/core/src/Luna/Pass/Desugaring/BlankArguments.hs +++ b/core/src/Luna/Pass/Desugaring/BlankArguments.hs @@ -10,6 +10,7 @@ import qualified Luna.Prelude as P import Data.TypeDesc import qualified Luna.IR.Repr.Vis as Vis import Luna.IR.Expr.Combinators +import Luna.IR.Layer.Redirect import Luna.IR.Function hiding (args) import Luna.IR.Expr.Layout.ENT hiding (Cons) import Luna.IR @@ -21,7 +22,7 @@ import Control.Monad (foldM) data BlankDesugaring type instance Abstract BlankDesugaring = BlankDesugaring type instance Inputs Net BlankDesugaring = '[AnyExpr, AnyExprLink] -type instance Inputs Layer BlankDesugaring = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Type, AnyExpr // Succs] +type instance Inputs Layer BlankDesugaring = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Type, AnyExpr // Succs, AnyExpr // Redirect] type instance Inputs Attr BlankDesugaring = '[UniqueNameGen, UsedVars] type instance Inputs Event BlankDesugaring = '[] diff --git a/core/src/Luna/Pass/Inference/FunctionResolution.hs b/core/src/Luna/Pass/Inference/FunctionResolution.hs index c58bea6ffee5..5f1296a1d682 100644 --- a/core/src/Luna/Pass/Inference/FunctionResolution.hs +++ b/core/src/Luna/Pass/Inference/FunctionResolution.hs @@ -7,6 +7,7 @@ import Luna.IR.Imports import Luna.IR.Module.Definition as Module import Luna.IR import Luna.IR.Expr.Combinators +import Luna.IR.Layer.Redirect import Luna.IR.Name (Name) import qualified Data.Map as Map import Data.Map (Map) @@ -35,7 +36,7 @@ data FunctionResolution type instance Abstract FunctionResolution = FunctionResolution type instance Inputs Net FunctionResolution = '[AnyExpr, AnyExprLink] -type instance Inputs Layer FunctionResolution = '[AnyExpr // Model, AnyExpr // Type, AnyExpr // Succs, AnyExpr // UID, AnyExprLink // Model, AnyExprLink // UID] +type instance Inputs Layer FunctionResolution = '[AnyExpr // Model, AnyExpr // Type, AnyExpr // Succs, AnyExpr // UID, AnyExprLink // Model, AnyExprLink // UID, AnyExpr // Redirect] type instance Inputs Attr FunctionResolution = '[CurrentVar, Imports] type instance Inputs Event FunctionResolution = '[] From f51b24e0b3d0a5837ab5cd035f181775d7a7037d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Tue, 24 Jan 2017 12:19:51 +0100 Subject: [PATCH 13/13] Move MethodResolution to its own file --- .../test/Luna/Pass/AccessorFunctionSpec.hs | 89 +------------ .../Luna/Pass/Inference/MethodResolution.hs | 121 ++++++++++++++++++ 2 files changed, 122 insertions(+), 88 deletions(-) create mode 100644 core/src/Luna/Pass/Inference/MethodResolution.hs diff --git a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs index c0c0408eaeaf..b2c8a68a7fdb 100644 --- a/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs +++ b/core/diag/test/Luna/Pass/AccessorFunctionSpec.hs @@ -33,6 +33,7 @@ import Luna.IR.Runner import Luna.Pass.Sugar.Construction import Luna.IR import Luna.TestUtils +import Luna.Pass.Inference.MethodResolution import Luna.Pass.Inference.FunctionResolution (ImportError(..), lookupSym) import System.Log import Control.Monad (foldM) @@ -40,94 +41,6 @@ import Type.Any (AnyType) -newtype CurrentAcc = CurrentAcc (Expr Acc) - - -data AccessorFunction -type instance Abstract AccessorFunction = AccessorFunction -type instance Inputs Net AccessorFunction = '[AnyExpr, AnyExprLink] -type instance Inputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Type, AnyExpr // Succs, AnyExpr // Redirect] -type instance Inputs Attr AccessorFunction = '[CurrentAcc, Imports] -type instance Inputs Event AccessorFunction = '[] - -type instance Outputs Net AccessorFunction = '[AnyExpr, AnyExprLink] -type instance Outputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Succs, AnyExpr // Type, AnyExpr // Redirect] -type instance Outputs Attr AccessorFunction = '[] -type instance Outputs Event AccessorFunction = '[New // AnyExpr, New // AnyExprLink, Import // AnyExpr, Import // AnyExprLink, Delete // AnyExprLink] - -type instance Preserves AccessorFunction = '[] - - -data AccessorError = MethodNotFound P.String - | AmbiguousType - deriving (Eq, Show) - -importAccessor :: _ => SubPass AccessorFunction m (Maybe AccessorError) -importAccessor = do - res <- importAccessor' - case res of - Left err -> return $ Just err - Right (_self, _body) -> return Nothing - -importAccessor' :: _ => SubPass AccessorFunction m (Either AccessorError (SomeExpr, SomeExpr)) -importAccessor' = do - CurrentAcc acc <- readAttr - match acc $ \case - Acc n v -> do - v' <- source v - tl <- readLayer @Type v' - t <- source tl - match t $ \case - Cons cls _args -> do - classNameExpr <- source cls - methodNameExpr <- source n - method <- importMethod classNameExpr methodNameExpr - case method of - Left SymbolNotFound -> do - methodName <- view lit <$> match' methodNameExpr - return $ Left $ MethodNotFound methodName - Right (ImportedMethod self body) -> do - replaceNode self v' - reconnectLayer' @Redirect (Just (unsafeGeneralize body :: Expr Draft)) acc - unifyTypes acc body - unifyTypes self v' - return $ Right (self, body) - _ -> return $ Left AmbiguousType - -unifyTypes :: _ => Expr _ -> Expr _ -> SubPass AccessorFunction m (Expr _) -unifyTypes e1 e2 = do - t1 <- readLayer @Type e1 >>= source - t2 <- readLayer @Type e2 >>= source - unify t1 t2 - -data ImportedMethod = ImportedMethod { self :: SomeExpr, body :: SomeExpr } - -importMethod :: _ => Expr _ -> Expr _ -> SubPass AccessorFunction m (Either ImportError ImportedMethod) -importMethod classExpr methodNameExpr = do - className <- fmap fromString (view lit <$> match' classExpr) - methodName <- fmap fromString (view lit <$> match' methodNameExpr) - imports <- readAttr @Imports - let method = (lookupClass className >=> lookupMethod methodName) imports - case method of - Left err -> return $ Left err - Right (Method self body) -> do - translator <- importTranslator body - bodyExpr <- importFunction body - return $ Right $ ImportedMethod (translator self) bodyExpr - -lookupClass :: Name -> Imports -> Either ImportError Class -lookupClass n imps = case matchedModules of - [] -> Left SymbolNotFound - [(_, Just f)] -> Right f - matches -> Left . SymbolAmbiguous $ fst <$> matches - where modulesWithMatchInfo = (over _2 $ flip Module.lookupClass n) <$> Map.assocs (unwrap imps) - matchedModules = filter (isJust . snd) modulesWithMatchInfo - -lookupMethod :: Name -> Class -> Either ImportError Method -lookupMethod n cls = case Map.lookup n (cls ^. methods) of - Just m -> Right m - _ -> Left SymbolNotFound - testSuccess :: _ => SubPass TestPass _ _ testSuccess = do one <- integer (1::Int) diff --git a/core/src/Luna/Pass/Inference/MethodResolution.hs b/core/src/Luna/Pass/Inference/MethodResolution.hs new file mode 100644 index 000000000000..8039a203a3a1 --- /dev/null +++ b/core/src/Luna/Pass/Inference/MethodResolution.hs @@ -0,0 +1,121 @@ +{-# LANGUAGE PartialTypeSignatures #-} + +module Luna.Pass.Inference.MethodResolution where + +import Luna.Pass hiding (compile) +import qualified Luna.Pass as Pass +import Control.Monad.Raise (MonadException(..), tryAll) +import qualified Luna.IR.Repr.Vis as Vis + +import qualified Data.Set as Set (null) +import Luna.Prelude hiding (String, s, new) +import qualified Luna.Prelude as P +import Data.Maybe (isJust) +import Data.TypeDesc +import qualified Luna.IR.Repr.Vis as Vis +import Luna.IR.Expr.Combinators +import Luna.IR.Imports +import qualified Luna.IR.Module.Definition as Module +import qualified Data.Map as Map +import Luna.IR.Function hiding (args) +import Luna.IR.Function.Definition +import Luna.IR.Expr.Layout +import Luna.IR.Layer.Redirect +import Luna.IR.Expr.Layout.ENT hiding (Cons) +import Luna.IR.Name (Name) +import Luna.IR.Class.Method (Method(..)) +import Luna.IR.Class.Definition +import Luna.Pass.Sugar.Construction +import Luna.IR +import Luna.Pass.Inference.FunctionResolution (ImportError(..), lookupSym) +import Control.Monad (foldM) +import Type.Any (AnyType) + + +newtype CurrentAcc = CurrentAcc (Expr Acc) + + +data AccessorFunction +type instance Abstract AccessorFunction = AccessorFunction +type instance Inputs Net AccessorFunction = '[AnyExpr, AnyExprLink] +type instance Inputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Type, AnyExpr // Succs, AnyExpr // Redirect] +type instance Inputs Attr AccessorFunction = '[CurrentAcc, Imports] +type instance Inputs Event AccessorFunction = '[] + +type instance Outputs Net AccessorFunction = '[AnyExpr, AnyExprLink] +type instance Outputs Layer AccessorFunction = '[AnyExpr // Model, AnyExprLink // Model, AnyExpr // Succs, AnyExpr // Type, AnyExpr // Redirect] +type instance Outputs Attr AccessorFunction = '[] +type instance Outputs Event AccessorFunction = '[New // AnyExpr, New // AnyExprLink, Import // AnyExpr, Import // AnyExprLink, Delete // AnyExprLink] + +type instance Preserves AccessorFunction = '[] + + +data AccessorError = MethodNotFound P.String + | AmbiguousType + deriving (Eq, Show) + +importAccessor :: MonadPassManager m => SubPass AccessorFunction m (Maybe AccessorError) +importAccessor = do + res <- importAccessor' + case res of + Left err -> return $ Just err + Right (_self, _body) -> return Nothing + +importAccessor' :: MonadPassManager m => SubPass AccessorFunction m (Either AccessorError (SomeExpr, SomeExpr)) +importAccessor' = do + CurrentAcc acc <- readAttr + match acc $ \case + Acc n v -> do + v' <- source v + tl <- readLayer @Type v' + t <- source tl + match t $ \case + Cons cls _args -> do + classNameExpr <- source cls + methodNameExpr <- source n + method <- importMethod classNameExpr methodNameExpr + case method of + Left SymbolNotFound -> do + methodName <- view lit <$> match' methodNameExpr + return $ Left $ MethodNotFound methodName + Right (ImportedMethod self body) -> do + replaceNode self v' + reconnectLayer' @Redirect (Just (unsafeGeneralize body :: Expr Draft)) acc + unifyTypes acc body + unifyTypes self v' + return $ Right (self, body) + _ -> return $ Left AmbiguousType + +unifyTypes :: MonadPassManager m => Expr t -> Expr v -> SubPass AccessorFunction m () +unifyTypes e1 e2 = do + t1 <- readLayer @Type e1 >>= source + t2 <- readLayer @Type e2 >>= source + void $ unify t1 t2 + +data ImportedMethod = ImportedMethod { self :: SomeExpr, body :: SomeExpr } + +importMethod :: (MonadPassManager m, _) => Expr l -> Expr l' -> SubPass AccessorFunction m (Either ImportError ImportedMethod) +importMethod classExpr methodNameExpr = do + className <- fmap fromString (view lit <$> match' classExpr) + methodName <- fmap fromString (view lit <$> match' methodNameExpr) + imports <- readAttr @Imports + let method = (lookupClass className >=> lookupMethod methodName) imports + case method of + Left err -> return $ Left err + Right (Method self body) -> do + translator <- importTranslator body + bodyExpr <- importFunction body + return $ Right $ ImportedMethod (translator self) bodyExpr + +lookupClass :: Name -> Imports -> Either ImportError Class +lookupClass n imps = case matchedModules of + [] -> Left SymbolNotFound + [(_, Just f)] -> Right f + matches -> Left . SymbolAmbiguous $ fst <$> matches + where modulesWithMatchInfo = (over _2 $ flip Module.lookupClass n) <$> Map.assocs (unwrap imps) + matchedModules = filter (isJust . snd) modulesWithMatchInfo + +lookupMethod :: Name -> Class -> Either ImportError Method +lookupMethod n cls = case Map.lookup n (cls ^. methods) of + Just m -> Right m + _ -> Left SymbolNotFound