2020-12-16 17:53:55 +03:00
|
|
|
{-# LANGUAGE DeriveGeneric #-}
|
|
|
|
|
2020-12-02 18:33:37 +03:00
|
|
|
module Types
|
|
|
|
( TypeMappings,
|
|
|
|
Ty (..),
|
|
|
|
showMaybeTy,
|
|
|
|
unifySignatures,
|
|
|
|
replaceTyVars,
|
|
|
|
areUnifiable,
|
|
|
|
typesDeleterFunctionType,
|
|
|
|
typesCopyFunctionType,
|
|
|
|
doesTypeContainTyVarWithName,
|
|
|
|
replaceConflicted,
|
|
|
|
lambdaEnvTy,
|
|
|
|
typeEqIgnoreLifetimes,
|
|
|
|
checkKinds,
|
|
|
|
-- SymPath imports
|
|
|
|
SymPath (..),
|
|
|
|
mangle,
|
|
|
|
pathToC,
|
|
|
|
consPath,
|
|
|
|
Kind,
|
|
|
|
tyToKind,
|
2020-12-07 12:09:39 +03:00
|
|
|
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,
|
2021-01-26 08:19:00 +03:00
|
|
|
promoteNumber,
|
2020-12-02 18:33:37 +03:00
|
|
|
)
|
|
|
|
where
|
2017-06-26 12:15:03 +03:00
|
|
|
|
2020-12-16 17:53:55 +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)
|
2020-12-16 17:53:55 +03:00
|
|
|
import GHC.Generics (Generic)
|
|
|
|
import qualified Map
|
2020-05-24 12:04:31 +03:00
|
|
|
import SymPath
|
2020-12-02 18:33:37 +03:00
|
|
|
import Util
|
|
|
|
|
2017-09-01 17:57:09 +03:00
|
|
|
--import Debug.Trace
|
2017-06-26 12:15:03 +03:00
|
|
|
|
|
|
|
-- | Carp types.
|
2020-12-02 18:33:37 +03:00
|
|
|
data Ty
|
|
|
|
= IntTy
|
|
|
|
| LongTy
|
|
|
|
| ByteTy
|
|
|
|
| BoolTy
|
|
|
|
| FloatTy
|
|
|
|
| DoubleTy
|
|
|
|
| StringTy
|
|
|
|
| PatternTy
|
|
|
|
| CharTy
|
2021-11-03 11:09:26 +03:00
|
|
|
| CCharTy
|
2020-12-02 18:33:37 +03:00
|
|
|
| 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
|
2020-12-02 18:33:37 +03:00
|
|
|
| TypeTy -- the type of types
|
|
|
|
| MacroTy
|
|
|
|
| DynamicTy -- the type of dynamic functions (used in REPL and macros)
|
|
|
|
| InterfaceTy
|
2021-03-04 09:29:52 +03:00
|
|
|
| CTy -- C literals
|
2020-12-02 18:33:37 +03:00
|
|
|
| Universe -- the type of types of types (the type of TypeTy)
|
2020-12-16 17:53:55 +03:00
|
|
|
deriving (Eq, Ord, Generic)
|
|
|
|
|
|
|
|
instance Hashable Ty
|
2017-06-26 12:15:03 +03:00
|
|
|
|
2020-05-05 18:23:25 +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.
|
2020-12-02 18:33:37 +03:00
|
|
|
data Kind
|
|
|
|
= Base
|
|
|
|
| Higher
|
|
|
|
deriving (Eq, Ord, Show)
|
2020-05-05 18:23:25 +03:00
|
|
|
|
|
|
|
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
|
2020-12-02 18:33:37 +03:00
|
|
|
tyToKind (PointerTy _) = Higher
|
|
|
|
tyToKind (RefTy _ _) = Higher -- Refs may also be treated as a data constructor
|
|
|
|
tyToKind _ = Base
|
2020-05-05 18:23:25 +03:00
|
|
|
|
2020-12-07 12:09:39 +03:00
|
|
|
-- | 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 ()
|
2020-12-09 08:19:28 +03:00
|
|
|
assignKinds ((StructTy (VarTy name) vars) : rest) arityMap =
|
2020-12-07 12:09:39 +03:00
|
|
|
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
|
2020-12-07 12:09:39 +03:00
|
|
|
where
|
2020-12-22 19:44:44 +03:00
|
|
|
next = vars ++ rest
|
|
|
|
kind = length vars
|
2020-12-09 08:19:28 +03:00
|
|
|
assignKinds ((VarTy v) : rest) arityMap =
|
2020-12-07 12:09:39 +03:00
|
|
|
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
|
2020-12-07 12:09:39 +03:00
|
|
|
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 ()
|
|
|
|
|
2019-10-17 13:02:49 +03:00
|
|
|
-- Exactly like '==' for Ty, but ignore lifetime parameter
|
|
|
|
typeEqIgnoreLifetimes :: Ty -> Ty -> Bool
|
|
|
|
typeEqIgnoreLifetimes (RefTy a _) (RefTy b _) = a == b
|
2020-02-07 19:09:23 +03:00
|
|
|
typeEqIgnoreLifetimes (FuncTy argsA retA _) (FuncTy argsB retB _) =
|
2020-12-02 18:33:37 +03:00
|
|
|
all (== True) (zipWith typeEqIgnoreLifetimes argsA argsB)
|
|
|
|
&& typeEqIgnoreLifetimes retA retB
|
2019-10-17 13:02:49 +03:00
|
|
|
typeEqIgnoreLifetimes (StructTy a tyVarsA) (StructTy b tyVarsB) =
|
2020-12-02 18:33:37 +03:00
|
|
|
a == b
|
|
|
|
&& all (== True) (zipWith typeEqIgnoreLifetimes tyVarsA tyVarsB)
|
2019-10-17 13:02:49 +03:00
|
|
|
typeEqIgnoreLifetimes a b = a == b
|
|
|
|
|
2020-12-09 08:19:28 +03:00
|
|
|
data SumTyCase = SumTyCase
|
|
|
|
{ caseName :: String,
|
|
|
|
caseMembers :: [(String, Ty)]
|
|
|
|
}
|
2020-12-02 18:33:37 +03:00
|
|
|
deriving (Show, Ord, Eq)
|
2018-10-30 16:33:06 +03:00
|
|
|
|
2020-11-24 16:06:42 +03:00
|
|
|
fnOrLambda :: String
|
2018-03-01 21:19:20 +03:00
|
|
|
fnOrLambda =
|
2018-02-12 16:33:51 +03:00
|
|
|
case platform of
|
|
|
|
Windows -> "Fn"
|
2020-05-11 14:31:00 +03:00
|
|
|
_ -> "Fn" -- "λ"
|
2018-02-12 15:58:33 +03:00
|
|
|
|
2017-06-26 12:15:03 +03:00
|
|
|
instance Show Ty where
|
2020-12-02 18:33:37 +03:00
|
|
|
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"
|
2021-11-03 11:09:26 +03:00
|
|
|
show CCharTy = "CChar"
|
2020-02-07 19:09:23 +03:00
|
|
|
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 ++ ")"
|
2020-12-02 18:33:37 +03:00
|
|
|
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
|
2020-12-02 18:33:37 +03:00
|
|
|
show (PointerTy p) = "(Ptr " ++ show p ++ ")"
|
|
|
|
show (RefTy r lt) =
|
2019-10-17 13:02:49 +03:00
|
|
|
-- case r of
|
|
|
|
-- PointerTy _ -> listView
|
|
|
|
-- StructTy _ _ -> listView
|
|
|
|
-- FuncTy _ _ -> listView
|
|
|
|
-- _ -> "&" ++ show r
|
|
|
|
-- where listView = "(Ref " ++ show r ++ ")"
|
|
|
|
"(Ref " ++ show r ++ " " ++ show lt ++ ")"
|
2020-12-02 18:33:37 +03:00
|
|
|
show StaticLifetimeTy = "StaticLifetime"
|
|
|
|
show MacroTy = "Macro"
|
|
|
|
show DynamicTy = "Dynamic"
|
2020-12-09 08:19:28 +03:00
|
|
|
show Universe = "Universe"
|
2021-03-04 09:29:52 +03:00
|
|
|
show CTy = "C"
|
2017-06-26 12:15:03 +03:00
|
|
|
|
|
|
|
showMaybeTy :: Maybe Ty -> String
|
|
|
|
showMaybeTy (Just t) = show t
|
2020-12-02 18:33:37 +03:00
|
|
|
showMaybeTy Nothing = "(missing-type)"
|
2017-06-26 12:15:03 +03:00
|
|
|
|
2018-06-12 11:57:59 +03:00
|
|
|
doesTypeContainTyVarWithName :: String -> Ty -> Bool
|
|
|
|
doesTypeContainTyVarWithName name (VarTy n) = name == n
|
2020-02-07 19:09:23 +03:00
|
|
|
doesTypeContainTyVarWithName name (FuncTy argTys retTy lt) =
|
2020-12-02 18:33:37 +03:00
|
|
|
doesTypeContainTyVarWithName name lt
|
|
|
|
|| any (doesTypeContainTyVarWithName name) argTys
|
|
|
|
|| doesTypeContainTyVarWithName name retTy
|
2020-05-04 18:18:23 +03:00
|
|
|
doesTypeContainTyVarWithName name (StructTy n tyArgs) = doesTypeContainTyVarWithName name n || any (doesTypeContainTyVarWithName name) tyArgs
|
2018-06-12 11:57:59 +03:00
|
|
|
doesTypeContainTyVarWithName name (PointerTy p) = doesTypeContainTyVarWithName name p
|
2020-12-02 18:33:37 +03:00
|
|
|
doesTypeContainTyVarWithName name (RefTy r lt) =
|
|
|
|
doesTypeContainTyVarWithName name r
|
|
|
|
|| doesTypeContainTyVarWithName name lt
|
2018-06-12 11:57:59 +03:00
|
|
|
doesTypeContainTyVarWithName _ _ = False
|
|
|
|
|
2020-06-02 07:40:49 +03:00
|
|
|
replaceConflicted :: String -> Ty -> Ty
|
2020-12-02 18:33:37 +03:00
|
|
|
replaceConflicted name (VarTy n) =
|
|
|
|
if n == name
|
2020-12-22 19:44:44 +03:00
|
|
|
then VarTy (n ++ "conflicted")
|
|
|
|
else VarTy n
|
2020-06-02 07:40:49 +03:00
|
|
|
replaceConflicted name (FuncTy argTys retTy lt) =
|
2020-12-02 18:33:37 +03:00
|
|
|
FuncTy
|
|
|
|
(map (replaceConflicted name) argTys)
|
|
|
|
(replaceConflicted name retTy)
|
|
|
|
(replaceConflicted name lt)
|
2020-06-02 07:40:49 +03:00
|
|
|
replaceConflicted name (StructTy n tyArgs) = StructTy (replaceConflicted name n) (map (replaceConflicted name) tyArgs)
|
|
|
|
replaceConflicted name (PointerTy p) = PointerTy (replaceConflicted name p)
|
2020-12-02 18:33:37 +03:00
|
|
|
replaceConflicted name (RefTy r lt) =
|
|
|
|
RefTy
|
|
|
|
(replaceConflicted name r)
|
|
|
|
(replaceConflicted name lt)
|
2020-11-26 00:12:57 +03:00
|
|
|
replaceConflicted _ t = t
|
2020-06-02 07:40:49 +03:00
|
|
|
|
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
|
2020-12-01 02:11:01 +03:00
|
|
|
unifySignatures at ct = Map.fromList (unify at ct)
|
2020-12-02 18:33:37 +03:00
|
|
|
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
|
2020-12-02 18:33:37 +03:00
|
|
|
| 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)
|
2020-08-08 08:24:04 +03:00
|
|
|
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
|
2019-10-17 13:02:49 +03:00
|
|
|
areUnifiable (RefTy a ltA) (RefTy b ltB) = areUnifiable a b && areUnifiable ltA ltB
|
2020-12-02 18:33:37 +03:00
|
|
|
areUnifiable RefTy {} _ = False
|
2020-02-07 19:09:23 +03:00
|
|
|
areUnifiable (FuncTy argTysA retTyA ltA) (FuncTy argTysB retTyB ltB)
|
2017-06-26 12:15:03 +03:00
|
|
|
| length argTysA /= length argTysB = False
|
2020-12-02 18:33:37 +03:00
|
|
|
| otherwise =
|
|
|
|
let argBools = zipWith areUnifiable argTysA argTysB
|
|
|
|
retBool = areUnifiable retTyA retTyB
|
|
|
|
ltBool = areUnifiable ltA ltB
|
|
|
|
in all (== True) (ltBool : retBool : argBools)
|
|
|
|
areUnifiable FuncTy {} _ = False
|
2021-09-04 16:08:51 +03:00
|
|
|
areUnifiable CTy _ = True
|
|
|
|
areUnifiable _ CTy = True
|
2020-12-02 18:33:37 +03:00
|
|
|
areUnifiable a b
|
|
|
|
| a == b = True
|
|
|
|
| otherwise = False
|
2017-06-26 12:15:03 +03:00
|
|
|
|
2020-05-05 18:23:25 +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 _) =
|
2020-05-06 05:52:03 +03:00
|
|
|
let argKinds = zipWith checkKinds argTysA argTysB
|
2020-05-05 18:23:25 +03:00
|
|
|
retKinds = tyToKind retTyA <= tyToKind retTyB
|
2020-12-02 18:33:37 +03:00
|
|
|
in all (== True) (retKinds : argKinds)
|
2020-05-06 05:52:03 +03:00
|
|
|
checkKinds t t' = tyToKind t <= tyToKind t'
|
2020-05-05 18:23:25 +03:00
|
|
|
|
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)
|
2020-02-07 19:09:23 +03:00
|
|
|
(FuncTy argTys retTy lt) -> FuncTy (map (replaceTyVars mappings) argTys) (replaceTyVars mappings retTy) (replaceTyVars mappings lt)
|
2020-08-08 08:24:04 +03:00
|
|
|
(StructTy name tyArgs) ->
|
2020-12-22 19:44:44 +03:00
|
|
|
case replaceTyVars mappings name of
|
2020-12-02 18:33:37 +03:00
|
|
|
-- 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)
|
2020-08-08 08:24:04 +03:00
|
|
|
_ -> StructTy (replaceTyVars mappings name) (fmap (replaceTyVars mappings) tyArgs)
|
2017-06-26 12:15:03 +03:00
|
|
|
(PointerTy x) -> PointerTy (replaceTyVars mappings x)
|
2019-10-17 13:02:49 +03:00
|
|
|
(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
|
2020-02-07 19:09:23 +03:00
|
|
|
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
|
2020-02-07 19:09:23 +03:00
|
|
|
typesDeleterFunctionType memberType = FuncTy [memberType] UnitTy StaticLifetimeTy
|
2017-12-19 00:32:33 +03:00
|
|
|
|
2018-06-19 12:13:16 +03:00
|
|
|
-- | 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)))
|
2021-01-26 08:19:00 +03:00
|
|
|
|
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 [] "")
|
|
|
|
|
2021-01-26 08:19:00 +03:00
|
|
|
-- 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)
|