git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Fix #620. More rigorous overlap check.
480b297Phil Freeman
examples/failing/OverlappingInstances.pursnew file+11
@@ -0,0 +1,11 @@
1+module OverlappingInstances where
2+
3+data A = A
4+
5+instance showA1 :: Show A where
6+ show A = "Instance 1"
7+
8+instance showA2 :: Show A where
9+ show A = "Instance 2"
10+
11+main = Debug.Trace.trace $ show A
src/Language/PureScript/TypeChecker/Types.hs+18−10
@@ -376,16 +376,18 @@ entails env moduleName context = solve (sortedNubBy canonicalizeDictionary (filt
376 --
376 --
377 checkOverlaps :: [DictionaryValue] -> Check Expr
377 checkOverlaps :: [DictionaryValue] -> Check Expr
378 checkOverlaps dicts =
378 checkOverlaps dicts =
379− case sortedNubBy dictTrace (chooseSimplestDictionaries dicts) of
379+ case [ (d1, d2) | d1 <- dicts, d2 <- dicts, d1 `overlapping` d2 ] of
380− [] -> throwError . strMsg $ "No instance found for " ++ show className ++ " " ++ unwords (map prettyPrintTypeAtom tys)
381− [_] -> return $ dictionaryValueToValue $ head dicts
382− (d1 : d2 : _) -> throwError . strMsg $ unlines
380+ (d1, d2) : _ -> throwError . strMsg $ unlines
383 [ "Overlapping instances found for " ++ show className ++ " " ++ unwords (map prettyPrintType tys) ++ "."
381 [ "Overlapping instances found for " ++ show className ++ " " ++ unwords (map prettyPrintType tys) ++ "."
384 , "For example:"
382 , "For example:"
385 , prettyPrintDictionaryValue d1
383 , prettyPrintDictionaryValue d1
386 , "and:"
384 , "and:"
387 , prettyPrintDictionaryValue d2
385 , prettyPrintDictionaryValue d2
388 ]
386 ]
387+ _ -> case chooseSimplestDictionaries dicts of
388+ [] -> throwError . strMsg $
389+ "No instance found for " ++ show className ++ " " ++ unwords (map prettyPrintTypeAtom tys)
390+ d : _ -> return $ dictionaryValueToValue d
389 -- Choose the simplest DictionaryValues from a list of candidates
391 -- Choose the simplest DictionaryValues from a list of candidates
390 -- The reason for this function is as follows:
392 -- The reason for this function is as follows:
391 -- When considering overlapping instances, we don't want to consider the same dictionary
393 -- When considering overlapping instances, we don't want to consider the same dictionary
@@ -402,13 +404,19 @@ entails env moduleName context = solve (sortedNubBy canonicalizeDictionary (filt
402 isSimpleDictionaryValue (DependentDictionaryValue _ ds) = all isSimpleDictionaryValue ds
404 isSimpleDictionaryValue (DependentDictionaryValue _ ds) = all isSimpleDictionaryValue ds
403 isSimpleDictionaryValue _ = True
405 isSimpleDictionaryValue _ = True
404 -- |
406 -- |
405− -- Get the "trace" of a DictionaryValue - that is, remove all SubclassDictionaryValue
407+ -- Check if two dictionaries are overlapping
406− -- data constructors
408+ --
409+ -- Dictionaries which are subclass dictionaries cannot overlap, since otherwise the overlap would have
410+ -- been caught when constructing superclass dictionaries.
407 --
411 --
408− dictTrace :: DictionaryValue -> DictionaryValue
412+ overlapping :: DictionaryValue -> DictionaryValue -> Bool
409− dictTrace (DependentDictionaryValue fnName dicts) = DependentDictionaryValue fnName $ map dictTrace dicts
413+ overlapping (LocalDictionaryValue nm1) (LocalDictionaryValue nm2) | nm1 == nm2 = False
414+ overlapping (GlobalDictionaryValue nm1) (GlobalDictionaryValue nm2) | nm1 == nm2 = False
415+ overlapping (DependentDictionaryValue nm1 ds1) (DependentDictionaryValue nm2 ds2)
416+ | nm1 == nm2 = any id $ zipWith overlapping ds1 ds2
410− dictTrace (SubclassDictionaryValue dict _ _) = dictTrace dict
417+ overlapping (SubclassDictionaryValue _ _ _) _ = False
411− dictTrace other = other
418+ overlapping _ (SubclassDictionaryValue _ _ _) = False
419+ overlapping _ _ = True
412 -- |
420 -- |
413 -- Render a DictionaryValue fit for human consumption in error messages
421 -- Render a DictionaryValue fit for human consumption in error messages
414 --
422 --