Skip to content

Commit b5e0972

Browse files
committed
fix(core): 🐛 Fix core typecheck incorrectly reporting unbound vars
It compared the variables' types which creates invalid behaviour as they won't always have the same type. This functionality will likely be changed soon when we do program elaboration
1 parent 6dec072 commit b5e0972

File tree

1 file changed

+26
-18
lines changed

1 file changed

+26
-18
lines changed

src/Elara/Core/TypeCheck.hs

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,23 @@ import Elara.Core.ANF qualified as ANF
1010

1111
import Data.Set qualified as Set
1212

13-
import Data.Map qualified as Map
1413
import Elara.AST.VarRef
15-
import Elara.Core (CoreExpr, Expr (..), TyCon, Var (..), typeArity)
14+
import Elara.Core (CoreExpr, Var (..))
1615
import Elara.Core qualified as Core
1716
import Elara.Core.Generic
1817
import Elara.Core.Module
19-
import Elara.Core.ToANF (fromANF, fromANFAtom, fromANFCExpr)
18+
import Elara.Core.ToANF (fromANF, fromANFAtom)
2019
import Elara.Data.Pretty
2120
import Elara.Error
2221
import Elara.Prim.Core
2322
import Polysemy
2423
import Polysemy.Error
25-
import Polysemy.State (State, evalState, gets, modify)
24+
import Polysemy.State (State, evalState, get, modify)
2625
import Polysemy.State.Extra (locally, scoped)
2726
import TODO (todo)
2827

2928
data TypeCheckError
30-
= UnboundVariable Var (Set.Set Var)
29+
= UnboundVariable Var (Set.Set (UnlocatedVarRef Text))
3130
| TypeMismatch
3231
{ expected :: Core.Type
3332
, actual :: Core.Type
@@ -48,24 +47,33 @@ instance Pretty TypeCheckError
4847
instance ReportableError TypeCheckError
4948

5049
data TcState = TcState
51-
{ scope :: Set.Set Var
50+
{ scope :: Set.Set (UnlocatedVarRef Text)
5251
-- ^ The 'Var' already holds the variable's type so we don't need to track that.
5352
-- However we do need to track scoping, as an optimisation could pull a variable out of scope
5453
}
5554

55+
addToScope :: Var -> TcState -> TcState
56+
addToScope (Id name _ _) s = s{scope = Set.insert name (scope s)}
57+
addToScope _ s = s
58+
59+
isInScope :: Var -> TcState -> Bool
60+
isInScope (Id name@(Local _) _ _) s = Set.member name (scope s)
61+
isInScope (Id (Global _) _ _) _ = True -- Global vars are always in scope
62+
isInScope _ _ = False
63+
5664
typeCheckCoreModule :: Member (Error TypeCheckError) r => CoreModule (Bind Var ANF.Expr) -> Sem r ()
5765
typeCheckCoreModule (CoreModule n m) = do
5866
let initialState = TcState{scope = mempty}
5967

6068
_ <- evalState initialState $ do
6169
for_ m $ \case
6270
CoreValue (NonRecursive (v, e)) -> scoped $ do
63-
modify (\s -> s{scope = Set.insert v (scope s)})
71+
modify (addToScope v)
6472
eType <- typeCheck e
6573
pure ()
6674
CoreValue (Recursive bs) -> scoped $ do
6775
for_ bs $ \(v, e) -> do
68-
modify (\s -> s{scope = Set.insert v (scope s)})
76+
modify (addToScope v)
6977

7078
for_ bs $ \(v, e) -> typeCheck e
7179
CoreType _ -> pure ()
@@ -81,12 +89,12 @@ typeCheck (ANF.Let bind in') = do
8189
case bind of
8290
NonRecursive (v, e) -> do
8391
eType <- typeCheckC e
84-
locally ((\s -> s{scope = Set.insert v (scope s)})) $
92+
locally (addToScope v) $
8593
typeCheck in'
86-
Recursive binds -> do
94+
Recursive binds -> scoped $ do
8795
let vars = map fst binds
88-
modify (\s -> s{scope = Set.union (Set.fromList vars) (scope s)})
89-
for_ binds $ \(v, e) -> typeCheckC e
96+
for_ vars $ \v -> modify (addToScope v)
97+
for_ binds $ \(_, e) -> typeCheckC e
9098
typeCheck in'
9199
typeCheck (ANF.CExpr cExp) = typeCheckC cExp
92100

@@ -103,7 +111,7 @@ typeCheckC (ANF.App f x) = do
103111
typeCheckC (ANF.AExpr aExp) = typeCheckA aExp
104112
typeCheckC (ANF.Match e of' alts) = scoped $ do
105113
eType <- typeCheckA e
106-
whenJust of' $ \v -> modify (\s -> s{scope = Set.insert v (scope s)})
114+
whenJust of' $ \v -> modify (addToScope v)
107115
altTypes <- for alts $ \(con, bs, e) -> do
108116
case con of
109117
Core.DEFAULT -> do
@@ -138,16 +146,16 @@ typeCheckLit lit = case lit of
138146
typeCheckA :: (Member (Error TypeCheckError) r, Member (State TcState) r) => ANF.AExpr Var -> Sem r Core.Type
139147
typeCheckA (ANF.Lit lit) = pure $ typeCheckLit lit
140148
-- Globally qualified vars are always in scope
141-
typeCheckA (ANF.Var (Id (Global _) t _)) = pure t
142149
typeCheckA (ANF.Var v) = do
143-
env <- gets scope
144-
case Set.member v env of
150+
env <- get
151+
152+
case isInScope v env of
145153
True -> pure (varType v)
146-
False -> throw $ UnboundVariable v env
154+
False -> throw $ UnboundVariable v (env.scope)
147155
typeCheckA (ANF.Lam v body) = do
148156
let t = varType v
149157

150-
eType <- locally (\s -> s{scope = Set.insert v (s.scope)}) $ typeCheck body
158+
eType <- locally (addToScope v) $ typeCheck body
151159
pure $ Core.FuncTy t eType
152160
typeCheckA (ANF.TyApp e t) = do
153161
eType <- typeCheckA e

0 commit comments

Comments
 (0)