infernu-0.0.0.1: Type inference and checker for JavaScript (experimental)

Safe HaskellNone
LanguageHaskell2010

Infernu.Infer

Synopsis

Documentation

test :: Exp Source -> String Source

Mutable variable being assigned incompatible types:

>>> let p = emptySource
>>> let fun args = EAbs p ("this":args)
>>> let var = EVar p
>>> let let' = ELet p
>>> let tuple = ETuple p
>>> let lit = ELit p
>>> let app a b = EApp p a [lit LitUndefined, b]
>>> let assign = EAssign p
>>> let array = EArray p

x is known to have type forall a. a -> a, and to have been used in a context requiring bool -> bool (e.g. `x True`)

we now try to assign x := y -> 2

This should fail because it "collapses" x to be Number -> Number which is not compatible with bool -> bool

>>> test $ let' "x" (fun ["z"] (var "z")) (let' "y" (tuple [app (var "x") (lit (LitNumber 2)), app (var "x") (lit (LitBoolean True))]) (assign "x" (fun ["y"] (lit (LitNumber 0))) (tuple [var "x", var "y"])))
":1:1*: Error: Could not unify: Number with Boolean"

The following should succeed because x is immutable and thus polymorphic:

>>> test $ let' "x" (fun ["z"] (var "z")) (let' "y" (tuple [app (var "x") (lit (LitNumber 2)), app (var "x") (lit (LitBoolean True))]) (tuple [var "x", var "y"]))
"(c.(d -> d), (Number, Boolean))"

The following should fail because x is mutable and therefore a monotype:

>>> test $ let' "x" (fun ["z"] (var "z")) (let' "y" (tuple [app (var "x") (lit (LitNumber 2)), app (var "x") (lit (LitBoolean True))]) (assign "x" (fun ["z1"] (var "z1")) (tuple [var "x", var "y"])))
":1:1*: Error: Could not unify: Number with Boolean"

The following should also succeed because "x" is only ever used like this: (x True). The second assignment to x is: x := z1 -> False, which is specific but matches the usage. Note that x's type is collapsed to: Boolean -> Boolean.

>>> test $ let' "x" (fun ["z"] (var "z")) (let' "y" (app (var "x") (lit (LitBoolean True))) (assign "x" (fun ["z1"] (lit (LitBoolean False))) (tuple [var "x", var "y"])))
"((Boolean -> Boolean), Boolean)"

| Tests a setter for x being called with something more specific than x's original definition: >>> :{ >>> test $ let' >>> "x" (fun ["a"] (var "a")) >>> (let' "setX" >>> (fun ["v"] >>> (let' >>> "_" (assign "x" (var "v") (var "x")) (lit (LitBoolean False)))) >>> (let' >>> "_" (app (var "setX") (fun ["a"] (lit (LitString "a")))) >>> (app (var "x") (lit (LitBoolean True))))) >>> :} ":1:1*: Error: Could not unify: String with Boolean"

>>> test $ tuple [lit (LitBoolean True), lit (LitNumber 2)]
"(Boolean, Number)"
>>> test $ let' "id" (fun ["x"] (var "x")) (assign "id" (fun ["y"] (var "y")) (var "id"))
"a.(b -> b)"
>>> test $ let' "id" (fun ["x"] (var "x")) (assign "id" (lit (LitBoolean True)) (var "id"))
":1:1*: Error: Could not unify: a.(b -> b) with Boolean"
>>> test $ let' "x" (lit (LitBoolean True)) (assign "x" (lit (LitBoolean False)) (var "x"))
"Boolean"
>>> test $ let' "x" (lit (LitBoolean True)) (assign "x" (lit (LitNumber 3)) (var "x"))
":1:1*: Error: Could not unify: Boolean with Number"
>>> test $ let' "x" (array [lit (LitBoolean True)]) (var "x")
"[Boolean]"
>>> test $ let' "x" (array [lit $ LitBoolean True, lit $ LitBoolean False]) (var "x")
"[Boolean]"
>>> test $ let' "x" (array []) (assign "x" (array []) (var "x"))
"[a]"
>>> test $ let' "x" (array [lit $ LitBoolean True, lit $ LitNumber 2]) (var "x")
":1:1*: Error: Could not unify: Number with Boolean"
>>> test $ let' "id" (fun ["x"] (let' "y" (var "x") (var "y"))) (app (var "id") (var "id"))
"c.(d -> d)"
>>> test $ let' "id" (fun ["x"] (let' "y" (var "x") (var "y"))) (app (app (var "id") (var "id")) (lit (LitNumber 2)))
"Number"
>>> test $ let' "id" (fun ["x"] (app (var "x") (var "x"))) (var "id")
":1:1*: Error: Occurs check failed: a in (a -> b)"
>>> test $ fun ["m"] (let' "y" (var "m") (let' "x" (app (var "y") (lit (LitBoolean True))) (var "x")))
"a.((Boolean -> b) -> b)"
>>> test $ app (lit (LitNumber 2)) (lit (LitNumber 2))
":1:1*: Error: Could not unify: Number with (Number -> a)"

EAssign tests >>> test $ let' "x" (fun ["y"] (lit (LitNumber 0))) (assign "x" (fun ["y"] (var "y")) (var "x")) "a.(Number -> Number)"

>>> test $ let' "x" (fun ["y"] (var "y")) (assign "x" (fun ["y"] (lit (LitNumber 0))) (var "x"))
"a.(Number -> Number)"
>>> test $ let' "x" (fun ["y"] (var "y")) (tuple [app (var "x") (lit (LitNumber 2)), app (var "x") (lit (LitBoolean True))])
"(Number, Boolean)"
>>> test $ let' "x" (fun ["y"] (var "y")) (app (var "x") (var "x"))
"c.(d -> d)"
>>> test $ let' "x" (fun ["a"] (var "a")) (let' "getX" (fun ["v"] (var "x")) (let' "setX" (fun ["v"] (let' "_" (assign "x" (var "v") (var "x")) (lit (LitBoolean True)))) (let' "_" (app (var "setX") (fun ["a"] (lit (LitString "a")))) (var "getX"))))
"e.(f -> d.(String -> String))"

class Pretty a where Source

Methods

prettyTab :: Int -> a -> String Source

Instances

Pretty Bool 
Pretty SourcePos 
Pretty InferState 
Pretty NameSource 
Pretty VarId 
Pretty ClassName 
Pretty TypeError 
Pretty Source 
Pretty Type 
Pretty RowTVar 
Pretty TConsName 
Pretty TypeId 
Pretty TBody 
Pretty TVarName
>>> prettyTab 0 (0 :: TVarName)
"a"
>>> prettyTab 0 (26 :: TVarName)
"aa"
Pretty LitVal 
Pretty EVarName 
Pretty GenInfo 
Pretty [String] 
(Pretty a, Pretty b) => Pretty [(a, b)] 
Pretty t => Pretty [TPred t] 
Pretty [Type] 
Pretty a => Pretty (Maybe a) 
Pretty k => Pretty (Set k) 
(Ord t, VarNames t, Pretty t) => Pretty (TScheme t) 
(VarNames t, Pretty t) => Pretty (TQual t) 
Pretty t => Pretty (TPred t) 
(Ord t, VarNames t, Pretty t) => Pretty (Class t) 
Pretty (FType Type) 
Pretty (Exp a) 
(Pretty a, Pretty b) => Pretty (Either a b) 
(Pretty a, Pretty b) => Pretty (a, b) 
(Pretty k, Pretty v) => Pretty (Map k v) 
(Show a, Show b) => Pretty (Gr a b) 
(Pretty a, Pretty b, Pretty c) => Pretty (a, b, c) 

pretty :: Pretty a => a -> String Source

minifyVars :: VarNames a => a -> a Source