merging parts of local environment
instance (Ord a, PosItem a, PrettyPrint a, Mergeable b)
merge = mergeMap id merge
improveDiag :: (PosItem a, PrettyPrint a) => a -> Diagnosis -> Diagnosis
improveDiag v d = d { diagString = let f:l = lines $ diagString d in
unlines $ (f ++ " of '" ++ showPretty v "'") : l
mergeMap :: (Ord a, PosItem a, PrettyPrint a) =>
(b -> b) -> (b -> b -> Result b)
mergeMap e f m1 m2 = foldM ( \ m (k, v) ->
let Result ds mu = f (e v) w
ns = map (improveDiag k) ds
Nothing -> Result ns $ Nothing
instance Mergeable a => Mergeable (Maybe a) where
Just v2 -> do v <- merge v1 v2
instance Mergeable ClassInfo where
merge = mergeA "super classes"
instance Mergeable Kind where
merge = mergeA "super kinds"
mergeTypeInfo :: TypeInfo -> TypeInfo -> Result TypeInfo
do k <- merge (typeKind t1) $ typeKind t2
o <- merge (otherTypeKinds t1) $ otherTypeKinds t2
s <- merge (superTypes t1) $ superTypes t2
d <- mergeTypeDefn (typeDefn t1) $ typeDefn t2
return $ TypeInfo k o s d
mergeTypeDefn :: TypeDefn -> TypeDefn -> Result TypeDefn
(TypeVarDefn 0, TypeVarDefn _) -> return d2
(TypeVarDefn _, TypeVarDefn 0) -> return d1
(TypeVarDefn c1, TypeVarDefn c2) -> do
c <- mergeA "TypeVarDefn" c1 c2
(TypeVarDefn _, _) -> fail "merge: TypeVarDefn"
(_, TypeVarDefn _) -> fail "merge: TypeVarDefn"
(_, DatatypeDefn _) -> return d2
(PreDatatype, _) -> fail "expected data type definition"
(_, PreDatatype) -> return d1
(NoTypeDefn, _) -> return d2
(_, NoTypeDefn) -> return d1
(AliasTypeDefn s1, AliasTypeDefn s2) ->
do s <- mergeScheme s1 s2
(Supertype v1 s1 t1, Supertype v2 s2 t2) ->
do s <- mergeScheme s1 s2
t <- mergeTerm Warning t1 t2
(_, _) -> mergeA "TypeDefn" d1 d2
instance Mergeable Vars where
merge = mergeA "variables for subtype definition"
mergeScheme :: TypeScheme -> TypeScheme -> Result TypeScheme
mergeScheme s1@(TypeScheme a1 t1 _)
s2@(TypeScheme a2 t2 _) =
mp v = mapArg $ zip v [(1::Int)..]
if null a1 && null a2 || isSingle a1 && isSingle a2 then
else if map (mp v1) a1 == map (mp v2) a2 then return s1
else fail ("differently bound type variables"
else fail ("wrong type scheme" ++ expected s1 s2)
instance Mergeable OpAttr where
merge (UnitOpAttr t1 p1) (UnitOpAttr t2 p2) =
do t <- mergeTerm Warning t1 t2
return $ UnitOpAttr t (p1 ++ p2)
merge a1 a2 = mergeA "attributes" a1 a2
instance Mergeable OpBrand where
merge Pred _ = return Pred
merge _ Pred = return Pred
instance Mergeable OpDefn where
merge VarDefn VarDefn = return VarDefn
merge VarDefn _ = fail "illegal redeclaration of a variable"
merge _ VarDefn = fail "illegal redeclaration as variable"
merge (NoOpDefn _) d = return d
merge d (NoOpDefn _) = return d
merge (ConstructData d1) (ConstructData _d2) = do
-- d <- mergeA "constructor target type" d1 d2
return $ ConstructData d1
merge (SelectData c1 d1) (SelectData c2 _d2) = do
-- d <- mergeA "selector source type" d1 d2
merge (Definition b1 d1) (Definition b2 d2) =
do d <- mergeTerm Hint d1 d2
merge _d1 _d2 = fail "illegal redefinition"
instance Eq a => Mergeable [a] where
return $ if any (e==) l2 then l3
mergeOpInfos :: TypeMap -> OpInfos -> OpInfos -> Result OpInfos
mergeOpInfos tm (OpInfos l1) (OpInfos l2) =
do l <- mergeOps (addUnit tm) l1 l2
mergeOps :: TypeMap -> [OpInfo] -> [OpInfo] -> Result [OpInfo]
mergeOps _ [] l = return l
mergeOps tm (o:os) l2 = do
let (es, us) = partition (isUnifiable tm 1
if null es then return (o : l1)
else do r <- mergeOpInfo tm o $ head es
mergeOpInfo :: TypeMap -> OpInfo -> OpInfo -> Result OpInfo
sc <- if instScheme tm 1 s2 s1 then return s1
else if instScheme tm 1 s1 s2 then return s2
else fail "overlapping but incompatible type schemes"
as <- merge (opAttrs o1) $ opAttrs o2
d <- merge (opDefn o1) $ opDefn o2
instance Mergeable Env where
do cMap <- merge (classMap e1) $ classMap e2
tMap <- mergeMap id mergeTypeInfo
(typeMap e1) $ typeMap e2
as <- mergeMap (OpInfos .
map (mapOpInfo (id, expandAlias tMap)) . opInfos)
(assumps e1) $ assumps e2
return initialEnv { classMap = cMap
mergeA :: (PrettyPrint a, Eq a) => String -> a -> a -> Result a
mergeA str t1 t2 = if t1 == t2 then return t1 else
fail ("different " ++ str ++ expected t1 t2)
mergeTerm :: DiagKind -> Term -> Term -> Result Term
mergeTerm k t1 t2 = if t1 == t2 then return t1 else
Result [Diag k ("different terms" ++ expected t1 t2)