Carp/src/Types.hs

382 lines
14 KiB
Haskell
Raw Normal View History

{-# LANGUAGE DeriveGeneric #-}
module Types
( TypeMappings,
Ty (..),
showMaybeTy,
unifySignatures,
replaceTyVars,
areUnifiable,
typesDeleterFunctionType,
typesCopyFunctionType,
doesTypeContainTyVarWithName,
replaceConflicted,
lambdaEnvTy,
typeEqIgnoreLifetimes,
checkKinds,
-- SymPath imports
SymPath (..),
mangle,
pathToC,
consPath,
Kind,
tyToKind,
areKindsConsistent,
Support defining types in modules (BREAKING) (#1084) * fix: don't set the inner env to globals in type mods Previously, we set the inner environment of a type generated module to the global env in cases where the overarching context didn't have an inner env. This leads to problems where by the recognition of modules is inconsistent, and one can't use the names of types as submodules in certain circumstances. This commit fixes that issue. * refactor: refactor primitiveDefmodule This refactor fixes a issues with meta information on submodules, for instance, sigs on submodule functions used to result in a compiler error about ambiguous identifiers. This fixes that. Unfortunately, I don't have a precise idea about what exactly was wrong with the original definition of this function. My suspicion is that the recursion originally altered submodule paths in the wrong way, but I'm not certain. In any case it's fixed. * fix: ensure macros are expanded in the correct module Previously, macro expansions folded over all forms after the top level form, without performing any context updates on encountered `defmodules`. This created an issue in which macro calls that produced new bindings, "meta stubs", were *hoisted* out of submodules and into the top-level module, creating duplicate definitions. This commit fixes that issue by adding a special case for defmodule in macroExpand. * fix: ensure submodules and globals don't conflict Previously, our module lookups during new module definition always eventually fell back to the global environment, which caused submodules that happen to share a name with a global module to be confused with the global module. This change fixes that, so now one can define both `Dynamic` (global) and `Foo.Dynamic` without issue. * fix: remove old prefixes from vector tests Commit 7b7cb5d1e replaced /= with a generic function. However, the vector tests still called the specific Vector variants of this function, which were removed when the generic was introduced. After recent changes, these calls are now (correctly) identified as erroneous. My guess is that they only worked in the past because of problems with our lookups. * chore: format code * feat!: support defining types in modules This commit adds support for defining types (using deftype) in modules. Previously, all types were hoisted to the top level of the type environment. After this commit, the type environment supports defining nested modules just like the value env, so, calling the following: ``` (defmodule Foo (deftype Bar Baz)) ``` Adds the following to the type env: ``` Foo : Module = { Bar : Type } ``` and the following to the value env: ``` Foo : Module = { Bar : Module = { Baz : (Fn [] Foo.Bar) copy : (Fn [(Ref Foo.Bar q)] Foo.Bar) delete : (Fn [Foo.Bar] ()) get-tag : (Fn [(Ref Foo.Bar q)] Int) prn : (Fn [(Ref Foo.Bar q)] String) str : (Fn [(Ref Foo.Bar q)] String) } } ``` Such a type is *distinct* from any type defined at the top level that happens to also have the name `Bar`. This commit also updates info and tests to account for types in modules. BREAKING CHANGE: This change is breaking since it alters the names of types that were previously defined in modules. A good example of this is the `Id` type in the `Color` module. Previously, one could refer to this type by simply typing `Id` since it was hoisted to the top level. Now it *must* be referred to by `Color.Id` since `Id` at the top level of the type env and `Color.Id` (Id in the color module) are considered to be distinct types. * chore: format code * refactor: use concat instead of intercalate * chore: remove excess parentheses * chore: Add todo to return IO () in printIfFound
2020-12-22 15:27:57 +03:00
createStructName,
getStructName,
getPathFromStructName,
getNameFromStructName,
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
getStructPath,
promoteNumber,
)
where
2017-06-26 12:15:03 +03:00
import Data.Hashable
Support defining types in modules (BREAKING) (#1084) * fix: don't set the inner env to globals in type mods Previously, we set the inner environment of a type generated module to the global env in cases where the overarching context didn't have an inner env. This leads to problems where by the recognition of modules is inconsistent, and one can't use the names of types as submodules in certain circumstances. This commit fixes that issue. * refactor: refactor primitiveDefmodule This refactor fixes a issues with meta information on submodules, for instance, sigs on submodule functions used to result in a compiler error about ambiguous identifiers. This fixes that. Unfortunately, I don't have a precise idea about what exactly was wrong with the original definition of this function. My suspicion is that the recursion originally altered submodule paths in the wrong way, but I'm not certain. In any case it's fixed. * fix: ensure macros are expanded in the correct module Previously, macro expansions folded over all forms after the top level form, without performing any context updates on encountered `defmodules`. This created an issue in which macro calls that produced new bindings, "meta stubs", were *hoisted* out of submodules and into the top-level module, creating duplicate definitions. This commit fixes that issue by adding a special case for defmodule in macroExpand. * fix: ensure submodules and globals don't conflict Previously, our module lookups during new module definition always eventually fell back to the global environment, which caused submodules that happen to share a name with a global module to be confused with the global module. This change fixes that, so now one can define both `Dynamic` (global) and `Foo.Dynamic` without issue. * fix: remove old prefixes from vector tests Commit 7b7cb5d1e replaced /= with a generic function. However, the vector tests still called the specific Vector variants of this function, which were removed when the generic was introduced. After recent changes, these calls are now (correctly) identified as erroneous. My guess is that they only worked in the past because of problems with our lookups. * chore: format code * feat!: support defining types in modules This commit adds support for defining types (using deftype) in modules. Previously, all types were hoisted to the top level of the type environment. After this commit, the type environment supports defining nested modules just like the value env, so, calling the following: ``` (defmodule Foo (deftype Bar Baz)) ``` Adds the following to the type env: ``` Foo : Module = { Bar : Type } ``` and the following to the value env: ``` Foo : Module = { Bar : Module = { Baz : (Fn [] Foo.Bar) copy : (Fn [(Ref Foo.Bar q)] Foo.Bar) delete : (Fn [Foo.Bar] ()) get-tag : (Fn [(Ref Foo.Bar q)] Int) prn : (Fn [(Ref Foo.Bar q)] String) str : (Fn [(Ref Foo.Bar q)] String) } } ``` Such a type is *distinct* from any type defined at the top level that happens to also have the name `Bar`. This commit also updates info and tests to account for types in modules. BREAKING CHANGE: This change is breaking since it alters the names of types that were previously defined in modules. A good example of this is the `Id` type in the `Color` module. Previously, one could refer to this type by simply typing `Id` since it was hoisted to the top level. Now it *must* be referred to by `Color.Id` since `Id` at the top level of the type env and `Color.Id` (Id in the color module) are considered to be distinct types. * chore: format code * refactor: use concat instead of intercalate * chore: remove excess parentheses * chore: Add todo to return IO () in printIfFound
2020-12-22 15:27:57 +03:00
import Data.List (intercalate)
2017-06-26 12:15:03 +03:00
import Data.Maybe (fromMaybe)
Support defining types in modules (BREAKING) (#1084) * fix: don't set the inner env to globals in type mods Previously, we set the inner environment of a type generated module to the global env in cases where the overarching context didn't have an inner env. This leads to problems where by the recognition of modules is inconsistent, and one can't use the names of types as submodules in certain circumstances. This commit fixes that issue. * refactor: refactor primitiveDefmodule This refactor fixes a issues with meta information on submodules, for instance, sigs on submodule functions used to result in a compiler error about ambiguous identifiers. This fixes that. Unfortunately, I don't have a precise idea about what exactly was wrong with the original definition of this function. My suspicion is that the recursion originally altered submodule paths in the wrong way, but I'm not certain. In any case it's fixed. * fix: ensure macros are expanded in the correct module Previously, macro expansions folded over all forms after the top level form, without performing any context updates on encountered `defmodules`. This created an issue in which macro calls that produced new bindings, "meta stubs", were *hoisted* out of submodules and into the top-level module, creating duplicate definitions. This commit fixes that issue by adding a special case for defmodule in macroExpand. * fix: ensure submodules and globals don't conflict Previously, our module lookups during new module definition always eventually fell back to the global environment, which caused submodules that happen to share a name with a global module to be confused with the global module. This change fixes that, so now one can define both `Dynamic` (global) and `Foo.Dynamic` without issue. * fix: remove old prefixes from vector tests Commit 7b7cb5d1e replaced /= with a generic function. However, the vector tests still called the specific Vector variants of this function, which were removed when the generic was introduced. After recent changes, these calls are now (correctly) identified as erroneous. My guess is that they only worked in the past because of problems with our lookups. * chore: format code * feat!: support defining types in modules This commit adds support for defining types (using deftype) in modules. Previously, all types were hoisted to the top level of the type environment. After this commit, the type environment supports defining nested modules just like the value env, so, calling the following: ``` (defmodule Foo (deftype Bar Baz)) ``` Adds the following to the type env: ``` Foo : Module = { Bar : Type } ``` and the following to the value env: ``` Foo : Module = { Bar : Module = { Baz : (Fn [] Foo.Bar) copy : (Fn [(Ref Foo.Bar q)] Foo.Bar) delete : (Fn [Foo.Bar] ()) get-tag : (Fn [(Ref Foo.Bar q)] Int) prn : (Fn [(Ref Foo.Bar q)] String) str : (Fn [(Ref Foo.Bar q)] String) } } ``` Such a type is *distinct* from any type defined at the top level that happens to also have the name `Bar`. This commit also updates info and tests to account for types in modules. BREAKING CHANGE: This change is breaking since it alters the names of types that were previously defined in modules. A good example of this is the `Id` type in the `Color` module. Previously, one could refer to this type by simply typing `Id` since it was hoisted to the top level. Now it *must* be referred to by `Color.Id` since `Id` at the top level of the type env and `Color.Id` (Id in the color module) are considered to be distinct types. * chore: format code * refactor: use concat instead of intercalate * chore: remove excess parentheses * chore: Add todo to return IO () in printIfFound
2020-12-22 15:27:57 +03:00
import Data.Text (pack, splitOn, unpack)
import GHC.Generics (Generic)
import qualified Map
import SymPath
import Util
--import Debug.Trace
2017-06-26 12:15:03 +03:00
-- | Carp types.
data Ty
= IntTy
| LongTy
| ByteTy
| BoolTy
| FloatTy
| DoubleTy
| StringTy
| PatternTy
| CharTy
| CCharTy
| FuncTy [Ty] Ty Ty -- In order of appearance: (1) Argument types, (2) Return type, (3) Lifetime
| VarTy String
| UnitTy
| ModuleTy
| PointerTy Ty
| RefTy Ty Ty -- second Ty is the lifetime
| StaticLifetimeTy
| StructTy Ty [Ty] -- the name (possibly a var) of the struct, and it's type parameters
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
| ConcreteNameTy SymPath -- the name of a struct
| TypeTy -- the type of types
| MacroTy
| DynamicTy -- the type of dynamic functions (used in REPL and macros)
| InterfaceTy
| CTy -- C literals
| Universe -- the type of types of types (the type of TypeTy)
deriving (Eq, Ord, Generic)
instance Hashable Ty
2017-06-26 12:15:03 +03:00
-- | Kinds checking
-- Carp's system is simple enough that we do not need to describe kinds by their airty.
-- After confirming two tys have either base or higher kind
-- unification checks are sufficient to determine whether their arities are compatible.
data Kind
= Base
| Higher
deriving (Eq, Ord, Show)
tyToKind :: Ty -> Kind
tyToKind (StructTy _ _) = Higher
2020-12-22 19:44:44 +03:00
tyToKind FuncTy {} = Higher -- the type of functions, consider the (->) constructor in Haskell
tyToKind (PointerTy _) = Higher
tyToKind (RefTy _ _) = Higher -- Refs may also be treated as a data constructor
tyToKind _ = Base
-- | Check whether or not the kinds of type variables are consistent.
-- This function will return Left as soon as a variable is used inconsistently,
-- reporting which variable triggered the issue.
-- If all variables are used consistently, it will process the whole list and
-- return ().
--
-- Kind arity matters; that is, `(f a b)` is not consistent with
-- `(f b)`. So long as the kind of a variable is the same across its uses,
-- everything is OK, for example:
-- ((Foo f a b) [x (f a) y (f b)])
-- is valid, and so is
-- ((Foo f a b) [x f y a z b])
-- But a definition such as:
-- ((Foo f a b) [x (f a b) y (f a)])
-- is inconsistent (kind of `f` differs) and so is
-- ((Foo f a b) [x (f a) y b (b a)])
-- (kind of `b` is inconsistent.
areKindsConsistent :: [Ty] -> Either String ()
areKindsConsistent typeVars =
assignKinds typeVars Map.empty
where
assignKinds :: [Ty] -> Map.Map String Int -> Either String ()
assignKinds ((StructTy (VarTy name) vars) : rest) arityMap =
case Map.lookup name arityMap of
Nothing -> assignKinds next (Map.insert name kind arityMap)
Just k ->
if k == kind
then assignKinds next arityMap
2020-12-22 19:44:44 +03:00
else Left name
where
2020-12-22 19:44:44 +03:00
next = vars ++ rest
kind = length vars
assignKinds ((VarTy v) : rest) arityMap =
case Map.lookup v arityMap of
Nothing -> assignKinds rest (Map.insert v kind arityMap)
Just k ->
if k == kind
then assignKinds rest arityMap
2020-12-22 19:44:44 +03:00
else Left v
where
kind = 0
assignKinds (FuncTy args ret _ : rest) arityMap =
assignKinds (args ++ ret : rest) arityMap
assignKinds ((PointerTy p) : rest) arityMap =
assignKinds (p : rest) arityMap
assignKinds ((RefTy r _) : rest) arityMap =
assignKinds (r : rest) arityMap
assignKinds (_ : rest) arityMap = assignKinds rest arityMap
assignKinds [] _ = pure ()
-- Exactly like '==' for Ty, but ignore lifetime parameter
typeEqIgnoreLifetimes :: Ty -> Ty -> Bool
typeEqIgnoreLifetimes (RefTy a _) (RefTy b _) = a == b
typeEqIgnoreLifetimes (FuncTy argsA retA _) (FuncTy argsB retB _) =
all (== True) (zipWith typeEqIgnoreLifetimes argsA argsB)
&& typeEqIgnoreLifetimes retA retB
typeEqIgnoreLifetimes (StructTy a tyVarsA) (StructTy b tyVarsB) =
a == b
&& all (== True) (zipWith typeEqIgnoreLifetimes tyVarsA tyVarsB)
typeEqIgnoreLifetimes a b = a == b
data SumTyCase = SumTyCase
{ caseName :: String,
caseMembers :: [(String, Ty)]
}
deriving (Show, Ord, Eq)
fnOrLambda :: String
2018-03-01 21:19:20 +03:00
fnOrLambda =
2018-02-12 16:33:51 +03:00
case platform of
Windows -> "Fn"
_ -> "Fn" -- "λ"
2018-02-12 15:58:33 +03:00
2017-06-26 12:15:03 +03:00
instance Show Ty where
show IntTy = "Int"
show FloatTy = "Float"
show DoubleTy = "Double"
show LongTy = "Long"
show ByteTy = "Byte"
show BoolTy = "Bool"
show StringTy = "String"
show PatternTy = "Pattern"
show CharTy = "Char"
show CCharTy = "CChar"
show (FuncTy argTys retTy StaticLifetimeTy) = "(" ++ fnOrLambda ++ " [" ++ joinWithComma (map show argTys) ++ "] " ++ show retTy ++ ")"
show (FuncTy argTys retTy lt) = "(" ++ fnOrLambda ++ " [" ++ joinWithComma (map show argTys) ++ "] " ++ show retTy ++ " " ++ show lt ++ ")"
show (VarTy t) = t
show UnitTy = "()"
show ModuleTy = "Module"
show TypeTy = "Type"
show InterfaceTy = "Interface"
2020-12-22 19:44:44 +03:00
show (StructTy s []) = show s
show (StructTy s typeArgs) = "(" ++ show s ++ " " ++ joinWithSpace (map show typeArgs) ++ ")"
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
show (ConcreteNameTy spath) = show spath
show (PointerTy p) = "(Ptr " ++ show p ++ ")"
show (RefTy r lt) =
-- case r of
-- PointerTy _ -> listView
-- StructTy _ _ -> listView
-- FuncTy _ _ -> listView
-- _ -> "&" ++ show r
-- where listView = "(Ref " ++ show r ++ ")"
"(Ref " ++ show r ++ " " ++ show lt ++ ")"
show StaticLifetimeTy = "StaticLifetime"
show MacroTy = "Macro"
show DynamicTy = "Dynamic"
show Universe = "Universe"
show CTy = "C"
2017-06-26 12:15:03 +03:00
showMaybeTy :: Maybe Ty -> String
showMaybeTy (Just t) = show t
showMaybeTy Nothing = "(missing-type)"
2017-06-26 12:15:03 +03:00
doesTypeContainTyVarWithName :: String -> Ty -> Bool
doesTypeContainTyVarWithName name (VarTy n) = name == n
doesTypeContainTyVarWithName name (FuncTy argTys retTy lt) =
doesTypeContainTyVarWithName name lt
|| any (doesTypeContainTyVarWithName name) argTys
|| doesTypeContainTyVarWithName name retTy
doesTypeContainTyVarWithName name (StructTy n tyArgs) = doesTypeContainTyVarWithName name n || any (doesTypeContainTyVarWithName name) tyArgs
doesTypeContainTyVarWithName name (PointerTy p) = doesTypeContainTyVarWithName name p
doesTypeContainTyVarWithName name (RefTy r lt) =
doesTypeContainTyVarWithName name r
|| doesTypeContainTyVarWithName name lt
doesTypeContainTyVarWithName _ _ = False
replaceConflicted :: String -> Ty -> Ty
replaceConflicted name (VarTy n) =
if n == name
2020-12-22 19:44:44 +03:00
then VarTy (n ++ "conflicted")
else VarTy n
replaceConflicted name (FuncTy argTys retTy lt) =
FuncTy
(map (replaceConflicted name) argTys)
(replaceConflicted name retTy)
(replaceConflicted name lt)
replaceConflicted name (StructTy n tyArgs) = StructTy (replaceConflicted name n) (map (replaceConflicted name) tyArgs)
replaceConflicted name (PointerTy p) = PointerTy (replaceConflicted name p)
replaceConflicted name (RefTy r lt) =
RefTy
(replaceConflicted name r)
(replaceConflicted name lt)
2020-11-26 00:12:57 +03:00
replaceConflicted _ t = t
2017-06-26 12:15:03 +03:00
-- | Map type variable names to actual types, eg. t0 => Int, t1 => Float
type TypeMappings = Map.Map String Ty
-- | From two types, one with type variables and one without (e.g. (Fn ["t0"] "t1") and (Fn [Int] Bool))
-- create mappings that translate from the type variables to concrete types, e.g. "t0" => Int, "t1" => Bool
unifySignatures :: Ty -> Ty -> TypeMappings
unifySignatures at ct = Map.fromList (unify at ct)
where
unify :: Ty -> Ty -> [(String, Ty)]
unify (VarTy _) (VarTy _) = [] -- if a == b then [] else error ("Can't unify " ++ show a ++ " with " ++ show b)
unify (VarTy a) value = [(a, value)]
unify (StructTy v'@(VarTy _) aArgs) (StructTy n bArgs) = unify v' n ++ concat (zipWith unify aArgs bArgs)
unify (StructTy a@(ConcreteNameTy _) aArgs) (StructTy b bArgs)
| a == b = concat (zipWith unify aArgs bArgs)
| otherwise = [] -- error ("Can't unify " ++ a ++ " with " ++ b)
unify (StructTy _ _) _ = [] -- error ("Can't unify " ++ show a ++ " with " ++ show b)
unify (PointerTy a) (PointerTy b) = unify a b
unify (PointerTy _) _ = [] -- error ("Can't unify " ++ show a ++ " with " ++ show b)
unify (RefTy a ltA) (RefTy b ltB) = unify a b ++ unify ltA ltB
unify (RefTy _ _) _ = [] -- error ("Can't unify " ++ show a ++ " with " ++ show b)
unify (FuncTy argTysA retTyA ltA) (FuncTy argTysB retTyB ltB) =
let argToks = concat (zipWith unify argTysA argTysB)
retToks = unify retTyA retTyB
ltToks = unify ltA ltB
in ltToks ++ argToks ++ retToks
unify FuncTy {} _ = [] -- error ("Can't unify " ++ show a ++ " with " ++ show b)
unify a b
| a == b = []
| otherwise = [] -- error ("Can't unify " ++ show a ++ " with " ++ show b)
2017-06-26 12:15:03 +03:00
-- | Checks if two types will unify
areUnifiable :: Ty -> Ty -> Bool
areUnifiable (VarTy _) (VarTy _) = True
areUnifiable (VarTy _) _ = True
2017-10-25 20:17:53 +03:00
areUnifiable _ (VarTy _) = True
2017-06-26 12:15:03 +03:00
areUnifiable (StructTy a aArgs) (StructTy b bArgs)
| length aArgs /= length bArgs = False
| areUnifiable a b =
let argBools = zipWith areUnifiable aArgs bArgs
in all (== True) argBools
2017-06-26 12:15:03 +03:00
| otherwise = False
Make Structs and Functions unifiable This commit makes function types unifiable to *only* polymorphic constructors (StructTy with a VarTy name). This enables one to implement interfaces defined against constructors against functions so long as: - The number of function arguments match the number of type constructor arguments. Thus, one can define: ``` (definterface constructor (Fn [(f a b)] (f a b))) (defmodule Test (defn constructor [f] (the (Fn ([a b] a) f)))) ``` But how is this useful? Here's one scenario this corrects in practice. In Haskell, the `some` function is typed generically as `some :: f a -> f [a]`. `some` takes a type and successively applies it until it returns an empty value, then it returns a list of results of the applications. This is great for types that actually have state, such as parsers, but for many values of `f` it makes no sense. E.G. given a `Maybe` the function will never terminate, since `Maybe.Just x` will never transform into the empty value on its own. This problem is even worse when we don't have inherent laziness to help us short-circuit application where possible. In fact, using an obvious definition of `some`, a function is the only (non-bottom) type in the `f a` position that may lead to eventual termination without requiring rewriting `some` to explicitly match against values. One could tuck a function away in a type constructor and devise a clever enough instance of choice to make this work, but it's simpler to define it against a function. Another case: type equivalences. When types are unifiable with constructors, it gives us an easy way to define concepts generically across types and functions. ``` (definterface app (Fn [(f a) a] a)) (defmodule Func (defn app [f x] (f x))) (defmodule Maybe (defn app [m x] (match m (Maybe.Nothing) (Maybe.Nothing) _ (Maybe.Just x)))) :i app app : (Fn [(f a), a] a) = { Func.app Maybe.app } (definterface compose (Fn [(f a) (f b)] (f c))) (defmodule Func (defn compose [f g] (fn [x] (f (g x))))) :i Func.compose (Fn [(Fn [a] b c), (Fn [d] a c)] (Fn [d] b e)) ;; In this case, we define composition as the explicit application of ;; the product (defmodule Maybe (defn compose [ma mb] (let [x (match ma (Maybe.Nothing) (zero) (Maybe.Just a) a) y (match mb (Maybe.Nothing) (zero) (Maybe.Just b) b)] (Maybe.Just (Pair x y))))) :i compose compose : (Fn [(f a), (f b)] (f c)) = { Func.compose Maybe.compose } ``` In a more general sense, this would enable us to use functions as a constructor type, analogous to the use of (->) in haskell. The gist is, this commit will let us extend our higher-kinded generic functions to functions.
2020-05-08 06:59:43 +03:00
areUnifiable (StructTy (VarTy _) aArgs) (FuncTy bArgs _ _)
| length aArgs /= length bArgs = False
| otherwise = all (== True) (zipWith areUnifiable aArgs bArgs)
areUnifiable (StructTy (VarTy _) args) (RefTy _ _)
| length args == 2 = True
| otherwise = False
2017-06-26 12:15:03 +03:00
areUnifiable (StructTy _ _) _ = False
areUnifiable (PointerTy a) (PointerTy b) = areUnifiable a b
areUnifiable (PointerTy _) _ = False
areUnifiable (RefTy a ltA) (RefTy b ltB) = areUnifiable a b && areUnifiable ltA ltB
areUnifiable RefTy {} _ = False
areUnifiable (FuncTy argTysA retTyA ltA) (FuncTy argTysB retTyB ltB)
2017-06-26 12:15:03 +03:00
| length argTysA /= length argTysB = False
| otherwise =
let argBools = zipWith areUnifiable argTysA argTysB
retBool = areUnifiable retTyA retTyB
ltBool = areUnifiable ltA ltB
in all (== True) (ltBool : retBool : argBools)
areUnifiable FuncTy {} _ = False
areUnifiable CTy _ = True
areUnifiable _ CTy = True
areUnifiable a b
| a == b = True
| otherwise = False
2017-06-26 12:15:03 +03:00
-- Checks whether or not the kindedness of types match
-- Kinds are polymorphic constructors such as (f a)
-- Note that this disagrees with the notion of unifiablitity in areUnifiable
checkKinds :: Ty -> Ty -> Bool
-- Base < Higher
checkKinds (FuncTy argTysA retTyA _) (FuncTy argTysB retTyB _) =
let argKinds = zipWith checkKinds argTysA argTysB
retKinds = tyToKind retTyA <= tyToKind retTyB
in all (== True) (retKinds : argKinds)
checkKinds t t' = tyToKind t <= tyToKind t'
2017-06-26 12:15:03 +03:00
-- | Put concrete types into the places where there are type variables.
-- For example (Fn [a] b) => (Fn [Int] Bool)
-- NOTE: If a concrete type can't be found, the type variable will stay the same.
replaceTyVars :: TypeMappings -> Ty -> Ty
replaceTyVars mappings t =
case t of
(VarTy key) -> fromMaybe t (Map.lookup key mappings)
(FuncTy argTys retTy lt) -> FuncTy (map (replaceTyVars mappings) argTys) (replaceTyVars mappings retTy) (replaceTyVars mappings lt)
(StructTy name tyArgs) ->
2020-12-22 19:44:44 +03:00
case replaceTyVars mappings name of
-- special case, struct (f a b) mapped to (RefTy a lt)
-- We f in such a case to the full (Ref a lt) in constraints; we also still map
-- individual members a and b, as these need mappings since they may be
-- referred to in other places (e.g. (Fn [(f a b)] a)--without a mapping,
-- a would remain generic here.
2020-12-22 19:44:44 +03:00
(RefTy a lt) -> replaceTyVars mappings (RefTy a lt)
_ -> StructTy (replaceTyVars mappings name) (fmap (replaceTyVars mappings) tyArgs)
2017-06-26 12:15:03 +03:00
(PointerTy x) -> PointerTy (replaceTyVars mappings x)
(RefTy x lt) -> RefTy (replaceTyVars mappings x) (replaceTyVars mappings lt)
2017-06-26 12:15:03 +03:00
_ -> t
2017-09-06 10:10:13 +03:00
-- | The type of a type's copying function.
typesCopyFunctionType :: Ty -> Ty
typesCopyFunctionType memberType = FuncTy [RefTy memberType (VarTy "q")] memberType StaticLifetimeTy
2017-09-06 10:10:13 +03:00
-- | The type of a type's deleter function.
typesDeleterFunctionType :: Ty -> Ty
typesDeleterFunctionType memberType = FuncTy [memberType] UnitTy StaticLifetimeTy
-- | The type of environments sent to Lambdas (used in emitted C code)
lambdaEnvTy :: Ty
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
lambdaEnvTy = StructTy (ConcreteNameTy (SymPath [] "LambdaEnv")) []
Support defining types in modules (BREAKING) (#1084) * fix: don't set the inner env to globals in type mods Previously, we set the inner environment of a type generated module to the global env in cases where the overarching context didn't have an inner env. This leads to problems where by the recognition of modules is inconsistent, and one can't use the names of types as submodules in certain circumstances. This commit fixes that issue. * refactor: refactor primitiveDefmodule This refactor fixes a issues with meta information on submodules, for instance, sigs on submodule functions used to result in a compiler error about ambiguous identifiers. This fixes that. Unfortunately, I don't have a precise idea about what exactly was wrong with the original definition of this function. My suspicion is that the recursion originally altered submodule paths in the wrong way, but I'm not certain. In any case it's fixed. * fix: ensure macros are expanded in the correct module Previously, macro expansions folded over all forms after the top level form, without performing any context updates on encountered `defmodules`. This created an issue in which macro calls that produced new bindings, "meta stubs", were *hoisted* out of submodules and into the top-level module, creating duplicate definitions. This commit fixes that issue by adding a special case for defmodule in macroExpand. * fix: ensure submodules and globals don't conflict Previously, our module lookups during new module definition always eventually fell back to the global environment, which caused submodules that happen to share a name with a global module to be confused with the global module. This change fixes that, so now one can define both `Dynamic` (global) and `Foo.Dynamic` without issue. * fix: remove old prefixes from vector tests Commit 7b7cb5d1e replaced /= with a generic function. However, the vector tests still called the specific Vector variants of this function, which were removed when the generic was introduced. After recent changes, these calls are now (correctly) identified as erroneous. My guess is that they only worked in the past because of problems with our lookups. * chore: format code * feat!: support defining types in modules This commit adds support for defining types (using deftype) in modules. Previously, all types were hoisted to the top level of the type environment. After this commit, the type environment supports defining nested modules just like the value env, so, calling the following: ``` (defmodule Foo (deftype Bar Baz)) ``` Adds the following to the type env: ``` Foo : Module = { Bar : Type } ``` and the following to the value env: ``` Foo : Module = { Bar : Module = { Baz : (Fn [] Foo.Bar) copy : (Fn [(Ref Foo.Bar q)] Foo.Bar) delete : (Fn [Foo.Bar] ()) get-tag : (Fn [(Ref Foo.Bar q)] Int) prn : (Fn [(Ref Foo.Bar q)] String) str : (Fn [(Ref Foo.Bar q)] String) } } ``` Such a type is *distinct* from any type defined at the top level that happens to also have the name `Bar`. This commit also updates info and tests to account for types in modules. BREAKING CHANGE: This change is breaking since it alters the names of types that were previously defined in modules. A good example of this is the `Id` type in the `Color` module. Previously, one could refer to this type by simply typing `Id` since it was hoisted to the top level. Now it *must* be referred to by `Color.Id` since `Id` at the top level of the type env and `Color.Id` (Id in the color module) are considered to be distinct types. * chore: format code * refactor: use concat instead of intercalate * chore: remove excess parentheses * chore: Add todo to return IO () in printIfFound
2020-12-22 15:27:57 +03:00
createStructName :: [String] -> String -> String
2020-12-22 19:44:44 +03:00
createStructName path name = intercalate "." (path ++ [name])
Support defining types in modules (BREAKING) (#1084) * fix: don't set the inner env to globals in type mods Previously, we set the inner environment of a type generated module to the global env in cases where the overarching context didn't have an inner env. This leads to problems where by the recognition of modules is inconsistent, and one can't use the names of types as submodules in certain circumstances. This commit fixes that issue. * refactor: refactor primitiveDefmodule This refactor fixes a issues with meta information on submodules, for instance, sigs on submodule functions used to result in a compiler error about ambiguous identifiers. This fixes that. Unfortunately, I don't have a precise idea about what exactly was wrong with the original definition of this function. My suspicion is that the recursion originally altered submodule paths in the wrong way, but I'm not certain. In any case it's fixed. * fix: ensure macros are expanded in the correct module Previously, macro expansions folded over all forms after the top level form, without performing any context updates on encountered `defmodules`. This created an issue in which macro calls that produced new bindings, "meta stubs", were *hoisted* out of submodules and into the top-level module, creating duplicate definitions. This commit fixes that issue by adding a special case for defmodule in macroExpand. * fix: ensure submodules and globals don't conflict Previously, our module lookups during new module definition always eventually fell back to the global environment, which caused submodules that happen to share a name with a global module to be confused with the global module. This change fixes that, so now one can define both `Dynamic` (global) and `Foo.Dynamic` without issue. * fix: remove old prefixes from vector tests Commit 7b7cb5d1e replaced /= with a generic function. However, the vector tests still called the specific Vector variants of this function, which were removed when the generic was introduced. After recent changes, these calls are now (correctly) identified as erroneous. My guess is that they only worked in the past because of problems with our lookups. * chore: format code * feat!: support defining types in modules This commit adds support for defining types (using deftype) in modules. Previously, all types were hoisted to the top level of the type environment. After this commit, the type environment supports defining nested modules just like the value env, so, calling the following: ``` (defmodule Foo (deftype Bar Baz)) ``` Adds the following to the type env: ``` Foo : Module = { Bar : Type } ``` and the following to the value env: ``` Foo : Module = { Bar : Module = { Baz : (Fn [] Foo.Bar) copy : (Fn [(Ref Foo.Bar q)] Foo.Bar) delete : (Fn [Foo.Bar] ()) get-tag : (Fn [(Ref Foo.Bar q)] Int) prn : (Fn [(Ref Foo.Bar q)] String) str : (Fn [(Ref Foo.Bar q)] String) } } ``` Such a type is *distinct* from any type defined at the top level that happens to also have the name `Bar`. This commit also updates info and tests to account for types in modules. BREAKING CHANGE: This change is breaking since it alters the names of types that were previously defined in modules. A good example of this is the `Id` type in the `Color` module. Previously, one could refer to this type by simply typing `Id` since it was hoisted to the top level. Now it *must* be referred to by `Color.Id` since `Id` at the top level of the type env and `Color.Id` (Id in the color module) are considered to be distinct types. * chore: format code * refactor: use concat instead of intercalate * chore: remove excess parentheses * chore: Add todo to return IO () in printIfFound
2020-12-22 15:27:57 +03:00
getStructName :: Ty -> String
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
getStructName (StructTy (ConcreteNameTy spath) _) = show spath
Support defining types in modules (BREAKING) (#1084) * fix: don't set the inner env to globals in type mods Previously, we set the inner environment of a type generated module to the global env in cases where the overarching context didn't have an inner env. This leads to problems where by the recognition of modules is inconsistent, and one can't use the names of types as submodules in certain circumstances. This commit fixes that issue. * refactor: refactor primitiveDefmodule This refactor fixes a issues with meta information on submodules, for instance, sigs on submodule functions used to result in a compiler error about ambiguous identifiers. This fixes that. Unfortunately, I don't have a precise idea about what exactly was wrong with the original definition of this function. My suspicion is that the recursion originally altered submodule paths in the wrong way, but I'm not certain. In any case it's fixed. * fix: ensure macros are expanded in the correct module Previously, macro expansions folded over all forms after the top level form, without performing any context updates on encountered `defmodules`. This created an issue in which macro calls that produced new bindings, "meta stubs", were *hoisted* out of submodules and into the top-level module, creating duplicate definitions. This commit fixes that issue by adding a special case for defmodule in macroExpand. * fix: ensure submodules and globals don't conflict Previously, our module lookups during new module definition always eventually fell back to the global environment, which caused submodules that happen to share a name with a global module to be confused with the global module. This change fixes that, so now one can define both `Dynamic` (global) and `Foo.Dynamic` without issue. * fix: remove old prefixes from vector tests Commit 7b7cb5d1e replaced /= with a generic function. However, the vector tests still called the specific Vector variants of this function, which were removed when the generic was introduced. After recent changes, these calls are now (correctly) identified as erroneous. My guess is that they only worked in the past because of problems with our lookups. * chore: format code * feat!: support defining types in modules This commit adds support for defining types (using deftype) in modules. Previously, all types were hoisted to the top level of the type environment. After this commit, the type environment supports defining nested modules just like the value env, so, calling the following: ``` (defmodule Foo (deftype Bar Baz)) ``` Adds the following to the type env: ``` Foo : Module = { Bar : Type } ``` and the following to the value env: ``` Foo : Module = { Bar : Module = { Baz : (Fn [] Foo.Bar) copy : (Fn [(Ref Foo.Bar q)] Foo.Bar) delete : (Fn [Foo.Bar] ()) get-tag : (Fn [(Ref Foo.Bar q)] Int) prn : (Fn [(Ref Foo.Bar q)] String) str : (Fn [(Ref Foo.Bar q)] String) } } ``` Such a type is *distinct* from any type defined at the top level that happens to also have the name `Bar`. This commit also updates info and tests to account for types in modules. BREAKING CHANGE: This change is breaking since it alters the names of types that were previously defined in modules. A good example of this is the `Id` type in the `Color` module. Previously, one could refer to this type by simply typing `Id` since it was hoisted to the top level. Now it *must* be referred to by `Color.Id` since `Id` at the top level of the type env and `Color.Id` (Id in the color module) are considered to be distinct types. * chore: format code * refactor: use concat instead of intercalate * chore: remove excess parentheses * chore: Add todo to return IO () in printIfFound
2020-12-22 15:27:57 +03:00
getStructName (StructTy (VarTy name) _) = name
getStructName _ = ""
getPathFromStructName :: String -> [String]
getPathFromStructName structName =
2020-12-22 19:44:44 +03:00
let path = map unpack (splitOn (pack ".") (pack structName))
in if length path > 1 then init path else []
Support defining types in modules (BREAKING) (#1084) * fix: don't set the inner env to globals in type mods Previously, we set the inner environment of a type generated module to the global env in cases where the overarching context didn't have an inner env. This leads to problems where by the recognition of modules is inconsistent, and one can't use the names of types as submodules in certain circumstances. This commit fixes that issue. * refactor: refactor primitiveDefmodule This refactor fixes a issues with meta information on submodules, for instance, sigs on submodule functions used to result in a compiler error about ambiguous identifiers. This fixes that. Unfortunately, I don't have a precise idea about what exactly was wrong with the original definition of this function. My suspicion is that the recursion originally altered submodule paths in the wrong way, but I'm not certain. In any case it's fixed. * fix: ensure macros are expanded in the correct module Previously, macro expansions folded over all forms after the top level form, without performing any context updates on encountered `defmodules`. This created an issue in which macro calls that produced new bindings, "meta stubs", were *hoisted* out of submodules and into the top-level module, creating duplicate definitions. This commit fixes that issue by adding a special case for defmodule in macroExpand. * fix: ensure submodules and globals don't conflict Previously, our module lookups during new module definition always eventually fell back to the global environment, which caused submodules that happen to share a name with a global module to be confused with the global module. This change fixes that, so now one can define both `Dynamic` (global) and `Foo.Dynamic` without issue. * fix: remove old prefixes from vector tests Commit 7b7cb5d1e replaced /= with a generic function. However, the vector tests still called the specific Vector variants of this function, which were removed when the generic was introduced. After recent changes, these calls are now (correctly) identified as erroneous. My guess is that they only worked in the past because of problems with our lookups. * chore: format code * feat!: support defining types in modules This commit adds support for defining types (using deftype) in modules. Previously, all types were hoisted to the top level of the type environment. After this commit, the type environment supports defining nested modules just like the value env, so, calling the following: ``` (defmodule Foo (deftype Bar Baz)) ``` Adds the following to the type env: ``` Foo : Module = { Bar : Type } ``` and the following to the value env: ``` Foo : Module = { Bar : Module = { Baz : (Fn [] Foo.Bar) copy : (Fn [(Ref Foo.Bar q)] Foo.Bar) delete : (Fn [Foo.Bar] ()) get-tag : (Fn [(Ref Foo.Bar q)] Int) prn : (Fn [(Ref Foo.Bar q)] String) str : (Fn [(Ref Foo.Bar q)] String) } } ``` Such a type is *distinct* from any type defined at the top level that happens to also have the name `Bar`. This commit also updates info and tests to account for types in modules. BREAKING CHANGE: This change is breaking since it alters the names of types that were previously defined in modules. A good example of this is the `Id` type in the `Color` module. Previously, one could refer to this type by simply typing `Id` since it was hoisted to the top level. Now it *must* be referred to by `Color.Id` since `Id` at the top level of the type env and `Color.Id` (Id in the color module) are considered to be distinct types. * chore: format code * refactor: use concat instead of intercalate * chore: remove excess parentheses * chore: Add todo to return IO () in printIfFound
2020-12-22 15:27:57 +03:00
getNameFromStructName :: String -> String
getNameFromStructName structName = last (map unpack (splitOn (pack ".") (pack structName)))
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
getStructPath :: Ty -> SymPath
getStructPath (StructTy (ConcreteNameTy spath) _) = spath
getStructPath (StructTy (VarTy name) _) = (SymPath [] name)
getStructPath _ = (SymPath [] "")
-- N.B.: promoteNumber is only safe for numeric types!
promoteNumber :: Ty -> Ty -> Ty
promoteNumber a b | a == b = a
promoteNumber ByteTy other = other
promoteNumber other ByteTy = other
promoteNumber IntTy other = other
promoteNumber other IntTy = other
promoteNumber LongTy other = other
promoteNumber other LongTy = other
promoteNumber FloatTy other = other
promoteNumber other FloatTy = other
promoteNumber DoubleTy _ = DoubleTy
promoteNumber _ DoubleTy = DoubleTy
promoteNumber a b =
error ("promoteNumber called with non-numbers: " ++ show a ++ ", " ++ show b)