Content-Length: 494361 | pFad | http://github.com/purescript/purescript/commit/6431cd32119e50ac08243cb441c5e122fd9a5800

AF Allow instances that require `Fail` to be empty (#4490) · purescript/purescript@6431cd3 · GitHub
Skip to content

Commit 6431cd3

Browse files
authored
Allow instances that require Fail to be empty (#4490)
A class instance declaration that has `Prim.TypeError.Fail` as a constraint will never be used. In light of this, such instances are now allowed to have empty bodies even if the class has members. (Such instances are still allowed to declare all of their members, and it is still an error to specify some but not all members.)
1 parent cf53018 commit 6431cd3

File tree

5 files changed

+75
-20
lines changed

5 files changed

+75
-20
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
* Allow instances that require `Fail` to be empty
2+
3+
A class instance declaration that has `Prim.TypeError.Fail` as a constraint
4+
will never be used. In light of this, such instances are now allowed to have
5+
empty bodies even if the class has members.
6+
7+
(Such instances are still allowed to declare all of their members, and it is
8+
still an error to specify some but not all members.)

src/Language/PureScript/Sugar/TypeClasses.hs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module Language.PureScript.Sugar.TypeClasses
1111
import Prelude
1212

1313
import Control.Arrow (first, second)
14+
import Control.Monad (unless)
1415
import Control.Monad.Error.Class (MonadError(..))
1516
import Control.Monad.State (MonadState(..), StateT, evalStateT, modify)
1617
import Control.Monad.Supply.Class (MonadSupply)
@@ -336,26 +337,33 @@ typeInstanceDictionaryDeclaration sa@(ss, _) name mn deps className tys decls =
336337

337338
let declaredMembers = S.fromList $ mapMaybe declIdent decls
338339

339-
case filter (\(ident, _) -> not $ S.member ident declaredMembers) memberTypes of
340-
hd : tl -> throwError . errorMessage' ss $ MissingClassMember (hd NEL.:| tl)
341-
[] -> do
342-
-- Create values for the type instance members
343-
members <- zip (map typeClassMemberName decls) <$> traverse (memberToValue memberTypes) decls
344-
345-
-- Create the type of the dictionary
346-
-- The type is a record type, but depending on type instance dependencies, may be constrained.
347-
-- The dictionary itself is a record literal.
348-
superclassesDicts <- for typeClassSuperclasses $ \(Constraint _ superclass _ suTyArgs _) -> do
349-
let tyArgs = map (replaceAllTypeVars (zip (map fst typeClassArguments) tys)) suTyArgs
350-
pure $ Abs (VarBinder ss UnusedIdent) (DeferredDictionary superclass tyArgs)
351-
let superclasses = superClassDictionaryNames typeClassSuperclasses `zip` superclassesDicts
352-
353-
let props = Literal ss $ ObjectLiteral $ map (first mkString) (members ++ superclasses)
354-
dictTy = foldl srcTypeApp (srcTypeConstructor (fmap (coerceProperName . dictTypeName) className)) tys
355-
constrainedTy = quantify (foldr srcConstrainedType dictTy deps)
356-
dict = App (Constructor ss (fmap (coerceProperName . dictTypeName) className)) props
357-
result = ValueDecl sa name Private [] [MkUnguarded (TypedValue True dict constrainedTy)]
358-
return result
340+
-- Instance declarations with a Fail constraint are unreachable code, so
341+
-- we allow them to be empty.
342+
let unreachable = any ((C.Fail ==) . constraintClass) deps && null decls
343+
344+
unless unreachable $
345+
case filter (\(ident, _) -> not $ S.member ident declaredMembers) memberTypes of
346+
hd : tl -> throwError . errorMessage' ss $ MissingClassMember (hd NEL.:| tl)
347+
[] -> pure ()
348+
349+
-- Create values for the type instance members
350+
members <- zip (map typeClassMemberName decls) <$> traverse (memberToValue memberTypes) decls
351+
352+
-- Create the type of the dictionary
353+
-- The type is a record type, but depending on type instance dependencies, may be constrained.
354+
-- The dictionary itself is a record literal (unless unreachable, in which case it's undefined).
355+
superclassesDicts <- for typeClassSuperclasses $ \(Constraint _ superclass _ suTyArgs _) -> do
356+
let tyArgs = map (replaceAllTypeVars (zip (map fst typeClassArguments) tys)) suTyArgs
357+
pure $ Abs (VarBinder ss UnusedIdent) (DeferredDictionary superclass tyArgs)
358+
let superclasses = superClassDictionaryNames typeClassSuperclasses `zip` superclassesDicts
359+
360+
let props = Literal ss $ ObjectLiteral $ map (first mkString) (members ++ superclasses)
361+
dictTy = foldl srcTypeApp (srcTypeConstructor (fmap (coerceProperName . dictTypeName) className)) tys
362+
constrainedTy = quantify (foldr srcConstrainedType dictTy deps)
363+
dict = App (Constructor ss (fmap (coerceProperName . dictTypeName) className)) props
364+
mkTV = if unreachable then TypedValue False (Var nullSourceSpan C.I_undefined) else TypedValue True dict
365+
result = ValueDecl sa name Private [] [MkUnguarded (mkTV constrainedTy)]
366+
return result
359367

360368
where
361369

tests/purs/failing/4483.out

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Error found:
2+
at tests/purs/failing/4483.purs:10:1 - 11:24 (line 10, column 1 - line 11, column 24)
3+
4+
The following type class members have not been implemented:
5+
bar :: Int -> Int
6+
7+
in type class instance
8+
 
9+
 Main.Foo Int
10+
 
11+
12+
See https://github.com/purescript/documentation/blob/master/errors/MissingClassMember.md for more information,
13+
or to contribute content related to this error.
14+

tests/purs/failing/4483.purs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- @shouldFailWith MissingClassMember
2+
module Main where
3+
4+
import Prim.TypeError
5+
6+
class Foo t where
7+
foo :: t -> String
8+
bar :: Int -> t
9+
10+
instance fooInt :: Fail (Text "can't use this") => Foo Int where
11+
foo _ = "unreachable"
12+
-- bar is missing; you can get away with an empty instance here but not a
13+
-- half-implemented one

tests/purs/passing/4483.purs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module Main where
2+
3+
import Effect.Console (log)
4+
import Prim.TypeError
5+
6+
class Foo t where
7+
foo :: t -> String
8+
bar :: Int -> t
9+
10+
instance fooInt :: Fail (Text "can't use this") => Foo Int
11+
12+
main = log "Done"

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/purescript/purescript/commit/6431cd32119e50ac08243cb441c5e122fd9a5800

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy