shithub: MicroHs

Download patch

ref: 494ebd7139ae4ce6d84e3a35b12874246a72adb7
parent: 6e00abdd457f19f3ca2d55dc32f175b6f62aed90
author: Lennart Augustsson <lennart@augustsson.net>
date: Thu Sep 26 11:43:11 EDT 2024

Fix a bug where unification variables were matched to early in constraint solving.

--- a/src/MicroHs/TCMonad.hs
+++ b/src/MicroHs/TCMonad.hs
@@ -15,6 +15,7 @@
 import qualified MicroHs.IntMap as IM
 import MicroHs.State
 import MicroHs.SymTab
+import Debug.Trace
 
 -----------------------------------------------
 -- TC
@@ -30,6 +31,13 @@
 tcError = errorMessage
 
 instance MonadFail Identity where fail = error
+
+tcTrace :: String -> TC s ()
+--tcTrace _ = return ()
+tcTrace msg = do
+  s <- get
+  let s' = trace msg s
+  seq s' (put s')
 
 -----------------------------------------------
 -- Tables
--- a/src/MicroHs/TypeCheck.hs
+++ b/src/MicroHs/TypeCheck.hs
@@ -442,6 +442,7 @@
 
 addInstTable :: [InstDictC] -> T ()
 addInstTable ics = do
+--  tcTrace $ "addInstTable: " ++ show ics
   let
     -- Change type variable to unique unification variables.
     -- These unification variables will never leak, but as an extra caution
@@ -463,7 +464,7 @@
 
 addConstraint :: Ident -> EConstraint -> T ()
 addConstraint d ctx = do
---  traceM $ "addConstraint: " ++ showIdent d ++ " :: " ++ showEType ctx
+--  tcTrace $ "addConstraint: " ++ showIdent d ++ " :: " ++ showEType ctx
   ctx' <- expandSyn ctx
   modify $ \ ts -> ts{ constraints = (d, ctx') : constraints ts }
 
@@ -477,12 +478,12 @@
 
 withDict :: forall a . HasCallStack => Ident -> EConstraint -> T a -> T a
 withDict i c ta = do
---  traceM $ "+++ withDict enter " ++ show (i, c)
+--  tcTrace $ "+++ withDict enter " ++ show (i, c)
   ct <- gets ctxTables
   addDict (i, c)
   a <- ta
   putCtxTables ct
---  traceM $ "--- withDict leave " ++ show (i, c)
+--  tcTrace $ "--- withDict leave " ++ show (i, c)
   return a
 
 addDict :: (Ident, EConstraint) -> T ()
@@ -507,7 +508,7 @@
 addEqDict :: Ident -> EType -> EType -> T ()
 addEqDict _i t1 t2 = do
   is <- gets typeEqTable
---  traceM ("withEqDict: " ++ show (is, (t1,t2), (addTypeEq t1 t2 is)))
+--  tcTrace ("withEqDict: " ++ show (is, (t1,t2), (addTypeEq t1 t2 is)))
   putTypeEqTable (addTypeEq t1 t2 is)
 
 addMetaDict :: HasCallStack => Ident -> EConstraint -> T ()
@@ -782,7 +783,7 @@
             SLoc -> TRef -> EType -> T ()
 unifyVar loc r t = do
   mt <- getUVar r
---  traceM $ "unifyVar: " ++ show (r,t)
+--  tcTrace $ "unifyVar: " ++ show (r,t)
   case mt of
     Nothing -> unifyUnboundVar loc r t
     Just t' -> unify loc t' t
@@ -826,10 +827,10 @@
     Left            e -> do
 {-
       tcm <- gets tcMode
-      traceM ("TCMode=" ++ show tcm)
-      traceM ("Value table:\n" ++ show env)
+      tcTrace ("TCMode=" ++ show tcm)
+      tcTrace ("Value table:\n" ++ show env)
       tenv <- gets typeTable
-      traceM ("Type table:\n" ++ show tenv)
+      tcTrace ("Type table:\n" ++ show tenv)
 -}
       tcError (getSLoc i) e
 
@@ -844,7 +845,7 @@
   t' <- tInstForall vks t
   tInst ae t'
 tInst ae at | Just (ctx, t) <- getImplies at = do
-  --traceM $ "tInst: addConstraint: " ++ show ae ++ ", " ++ show d ++ " :: " ++ show ctx
+  --tcTrace $ "tInst: addConstraint: " ++ show ae ++ ", " ++ show d ++ " :: " ++ show ctx
   if eqExpr ae eCannotHappen then
     -- XXX Gruesome hack.  This avoid adding constraints in cases like
     --  (C a => a) -> T `subsCheck` b
@@ -948,13 +949,13 @@
 
 tcDefs :: ImpType -> [EDef] -> T [EDef]
 tcDefs impt ds = do
---  traceM ("tcDefs 1:\n" ++ showEDefs ds)
+--  tcTrace ("tcDefs 1:\n" ++ showEDefs ds)
   mapM_ tcAddInfix ds
   dst <- tcDefsType ds
---  traceM ("tcDefs 2:\n" ++ showEDefs dst)
+--  tcTrace ("tcDefs 2:\n" ++ showEDefs dst)
   mapM_ addTypeSyn dst
   dst' <- tcExpand impt dst
---  traceM ("tcDefs 3:\n" ++ showEDefs dst')
+--  tcTrace ("tcDefs 3:\n" ++ showEDefs dst')
   case impt of
     ImpNormal -> do
       setDefault dst'
@@ -981,7 +982,7 @@
   mapM_ (addTypeKind kindSigs) ds              -- Add the kind of each type to the environment
   dst <- mapM tcDefType ds                     -- Kind check all top level type expressions
 --  vars <- gets uvarSubst
---  traceM $ show vars
+--  tcTrace $ show vars
   vt <- gets valueTable
   let ent (Entry i t) = Entry i . mapEType def <$> derefUVar t
       def (EUVar _) = kType    -- default kind variables to Type
@@ -988,7 +989,7 @@
       def t = t
   vt' <- mapMSymTab ent vt
   putValueTable vt'
---  traceM $ "tcDefType value table:\n" ++ show vt'
+--  tcTrace $ "tcDefType value table:\n" ++ show vt'
   return dst
 
 -- Get all kind signatures, and do sort checking of them.
@@ -1005,9 +1006,9 @@
 tcExpand impt dst = withTypeTable $ do
   dsc <- concat <$> mapM (expandClass impt) dst       -- Expand all class definitions
   dsf <- concat <$> mapM expandField dsc              -- Add HasField instances
---  traceM $ showEDefs dsf
+--  tcTrace $ showEDefs dsf
   dsd <- concat <$> mapM doDeriving  dsf              -- Add derived instances
---  traceM $ showEDefs dsd
+--  tcTrace $ showEDefs dsd
   dsi <- concat <$> mapM expandInst  dsd              -- Expand all instance definitions
   return dsi
 
@@ -1239,7 +1240,7 @@
       qiCls = getAppCon cc
   let iInst = mkInstId loc cc
       sign = Sign [iInst] act
---  traceM ("expandInst " ++ show iInst)
+--  tcTrace ("expandInst " ++ show iInst)
 --  (e, _) <- tLookupV iCls
   ct <- gets classTable
 --  let qiCls = getAppCon e
@@ -1270,7 +1271,7 @@
 
 tcDefsValue :: [EDef] -> T [EDef]
 tcDefsValue defs = do
---  traceM $ "tcDefsValue: ------------ start"
+--  tcTrace $ "tcDefsValue: ------------ start"
   -- Gather up all type signatures, and put them in the environment.
   mapM_ addValueType defs
   let smap = M.fromList [ (i, ()) | Sign is _ <- defs, i <- is ]
@@ -1288,7 +1289,7 @@
   -- return inferred Sign
   signDefs <- mapM tcSCC sccs
   --  type check all definitions (the inferred ones will be rechecked)
---  traceM $ "tcDefsValue: ------------ check"
+--  tcTrace $ "tcDefsValue: ------------ check"
   defs' <- mapM (\ d -> do { tcReset; tcDefValue d}) defs
   return $ concat signDefs ++ defs'
 
@@ -1298,7 +1299,7 @@
   tcReset
   -- Invent type variables for the definitions
   xts <- mapM (\ (Fcn i _) -> (,) i <$> newUVar) fcns
-  --traceM $ "tInferDefs: " ++ show (map fst xts)
+  --tcTrace $ "tInferDefs: " ++ show (map fst xts)
   -- Temporarily extend the local environment with the type variables
   withExtVals xts $ do
     -- Infer types for all the Fcns, ignore the new bodies.
@@ -1316,7 +1317,7 @@
             t'' = addConstraints ctx' t'
             vs' = metaTvs [t'']
         t''' <- quantify vs' t''
-        --traceM $ "tInferDefs: " ++ showIdent i ++ " :: " ++ showEType t'''
+        --tcTrace $ "tInferDefs: " ++ showIdent i ++ " :: " ++ showEType t'''
         extValQTop i t'''
         return $ Sign [i] t'''
   mapM genTop xts
@@ -1332,7 +1333,7 @@
 addValueType :: EDef -> T ()
 addValueType adef = do
   mn <- gets moduleName
-  -- traceM ("addValueType: " ++ showEDefs [adef])
+  -- tcTrace ("addValueType: " ++ showEDefs [adef])
   let addConFields _     (Constr _ _ _ (Left _)) = return ()
       addConFields tycon (Constr _ _ _ (Right fs)) = mapM_ addField fs
         where addField (fld, _) = do
@@ -1380,7 +1381,7 @@
   extValETop iCon iConTy (ECon $ ConData cti (qualIdent mn iCon) [])
   let addMethod (BSign i t) = extValETop i (EForall True vks $ tApps qiCls (map (EVar . idKindIdent) vks) `tImplies` t) (EVar $ qualIdent mn i)
       addMethod _ = impossible
---  traceM ("addValueClass " ++ showEType (ETuple ctx))
+--  tcTrace ("addValueClass " ++ showEType (ETuple ctx))
   mapM_ addMethod meths
   -- Update class table, now with actual constructor type.
   addClassTable qiCls (vks, ctx, iConTy, methIds, mkIFunDeps (map idKindIdent vks) fds)
@@ -1396,15 +1397,16 @@
     Fcn i eqns -> do
       (_, t) <- tLookup "type signature" i
       t' <- expandSyn t
---      traceM $ "tcDefValue: " ++ showIdent i ++ " :: " ++ showExpr t'
---      traceM $ "tcDefValue:      " ++ showEDefs [adef]
+--      tcTrace $ "tcDefValue: ------- start " ++ showIdent i
+--      tcTrace $ "tcDefValue: " ++ showIdent i ++ " :: " ++ showExpr t'
+--      tcTrace $ "tcDefValue: " ++ showEDefs [adef]
       teqns <- tcEqns True t' eqns
---      traceM ("tcDefValue: after\n" ++ showEDefs [adef, Fcn i teqns])
+--      tcTrace ("tcDefValue: after\n" ++ showEDefs [adef, Fcn i teqns])
 --      cs <- gets constraints
---      traceM $ "tcDefValue: constraints: " ++ show cs
+--      tcTrace $ "tcDefValue: constraints: " ++ show cs
       checkConstraints
       mn <- gets moduleName
---      traceM $ "tcDefValue: " ++ showIdent i ++ " done"
+--      tcTrace $ "tcDefValue: " ++ showIdent i ++ " done"
       return $ Fcn (qualIdent mn i) teqns
     ForImp ie i t -> do
       mn <- gets moduleName
@@ -1420,7 +1422,7 @@
   let fvs = freeTyVars [t]                     -- free variables in t
       -- these are free, and need quantification.  eDummy indicates missing kind
       iks = map (\ i -> IdKind i eDummy) (fvs \\ bvs)
-  --when (not (null iks)) $ traceM ("tCheckTypeTImpl: " ++ show (t, eForall iks t))
+  --when (not (null iks)) $ tcTrace ("tCheckTypeTImpl: " ++ show (t, eForall iks t))
   tCheckTypeT tchk (eForall' False iks t)
 
 tCheckTypeT :: HasCallStack => EType -> EType -> T EType
@@ -1480,7 +1482,7 @@
 tCheckExpr :: HasCallStack =>
               EType -> Expr -> T Expr
 tCheckExpr t e | Just (ctx, t') <- getImplies t = do
---  traceM $ "tCheckExpr: " ++ show (e, ctx, t')
+--  tcTrace $ "tCheckExpr: " ++ show (e, ctx, t')
   d <- newADictIdent (getSLoc e)
   e' <- withDict d ctx $ tCheckExprAndSolve t' e
   return $ eLam [EVar d] e'
@@ -1512,9 +1514,9 @@
 tcExpr :: HasCallStack =>
           Expected -> Expr -> T Expr
 tcExpr mt ae = do
---  traceM ("tcExpr enter: " ++ showExpr ae)
+--  tcTrace ("tcExpr enter: " ++ showExpr ae)
   r <- tcExprR mt ae
---  traceM ("tcExpr exit: " ++ showExpr r)
+--  tcTrace ("tcExpr exit: " ++ showExpr r)
   return r
 tcExprR :: HasCallStack =>
            Expected -> Expr -> T Expr
@@ -1541,15 +1543,15 @@
                case t of
                  EUVar r -> fmap (fromMaybe t) (getUVar r)
                  _ -> return t
-             --traceM $ "EVar: " ++ showIdent i ++ " :: " ++ showExpr t ++ " = " ++ showExpr t' ++ " mt=" ++ show mt
+             --tcTrace $ "EVar: " ++ showIdent i ++ " :: " ++ showExpr t ++ " = " ++ showExpr t' ++ " mt=" ++ show mt
              instSigma loc e t' mt
 
     EApp f a -> do
---      traceM $ "txExpr(0) EApp: expr=" ++ show ae ++ ":: " ++ show mt
+--      tcTrace $ "txExpr(0) EApp: expr=" ++ show ae ++ ":: " ++ show mt
       (f', ft) <- tInferExpr f
---      traceM $ "tcExpr(1) EApp: f=" ++ show f ++ "; f'=" ++ show f' ++ " :: " ++ show ft
+--      tcTrace $ "tcExpr(1) EApp: f=" ++ show f ++ "; f'=" ++ show f' ++ " :: " ++ show ft
       (at, rt) <- unArrow loc ft
---      traceM $ "tcExpr(2) EApp: f=" ++ show f ++ " :: " ++ show ft ++ ", arg=" ++ show a ++ " :: " ++ show at ++ " retty=" ++ show rt
+--      tcTrace $ "tcExpr(2) EApp: f=" ++ show f ++ " :: " ++ show ft ++ ", arg=" ++ show a ++ " :: " ++ show at ++ " retty=" ++ show rt
       -- We want to do the unification of rt ant mt before checking the argument to
       -- have more type information.  See tests/Eq1.hs.
       -- But instSigma may transform the input expression, so we have to be careful.
@@ -1557,7 +1559,7 @@
           ugly = -1::Int
       etmp' <- instSigma loc etmp rt mt
       a' <- checkSigma a at
---      traceM $ "tcExpr(3) EApp: f = " ++ show f ++ " :: " ++ show ft ++ ", arg=" ++ show a' ++ " :: " ++ show at ++ " retty=" ++ show rt ++ " mt = " ++ show mt
+--      tcTrace $ "tcExpr(3) EApp: f = " ++ show f ++ " :: " ++ show ft ++ ", arg=" ++ show a' ++ " :: " ++ show at ++ " retty=" ++ show rt ++ " mt = " ++ show mt
       let res = EApp f' a'
       case etmp' of
         EUVar _ -> return res   -- instSigma did nothing, this is the common case
@@ -1610,7 +1612,7 @@
                   (f, ft) <- tInferExpr (EVar (mkIdentSLoc loc $ "fromString"))  -- XXX should have this qualified somehow
                   (_at, rt) <- unArrow loc ft
                   -- We don't need to check that _at is String, it's part of the fromString type.
-                  --traceM ("LStr " ++ show (loc, r))
+                  --tcTrace ("LStr " ++ show (loc, r))
                   instSigma loc (EApp f ae) rt mt
             -- Not LInteger, LRat, LStr
             _ -> tcLit mt loc lit
@@ -1941,7 +1943,7 @@
   let loc = getSLoc eqns
   f <- newIdent loc "fcnS"
   (eqns', ds) <- solveAndDefault top $ mapM (tcEqn t) eqns
---  traceM $ "tcEqns done: " ++ showEBind (BFcn dummyIdent eqns')
+--  tcTrace $ "tcEqns done: " ++ showEBind (BFcn dummyIdent eqns')
   case ds of
     [] -> return eqns'
     _  -> do
@@ -1955,7 +1957,7 @@
 tcEqn t eqn =
   case eqn of
     Eqn ps alts -> tcPats t ps $ \ t' ps' -> do
---      traceM $ "tcEqn " ++ show ps ++ " ---> " ++ show ps'
+--      tcTrace $ "tcEqn " ++ show ps ++ " ---> " ++ show ps'
       alts' <- tcAlts t' alts
       return (Eqn ps' alts')
 
@@ -1971,7 +1973,7 @@
 tcAlts t (EAlts alts bs) =
 --  trace ("tcAlts: bs in " ++ showEBinds bs) $
   tcBinds bs $ \ bs' -> do
---    traceM ("tcAlts: bs out " ++ showEBinds bbs)
+--    tcTrace ("tcAlts: bs out " ++ showEBinds bbs)
     alts' <- mapM (tcAlt t) alts
     return (EAlts alts' bs')
 
@@ -2038,7 +2040,7 @@
 tCheckPatC t p@(EVar v) ta | not (isConIdent v) = do  -- simple special case
   withExtVals [(v, t)] $ ta p
 tCheckPatC t app ta = do
---  traceM $ "tCheckPatC: " ++ show app ++ " :: " ++ show t
+--  tcTrace $ "tCheckPatC: " ++ show app ++ " :: " ++ show t
   app' <- dsEFields app
   let vs = patVars app'
   multCheck vs
@@ -2045,10 +2047,10 @@
   env <- mapM (\ v -> (,) v <$> newUVar) vs
   withExtVals env $ do
     (_sks, ds, pp) <- tCheckPat t app'
---    traceM ("tCheckPatC: " ++ show pp)
+--    tcTrace ("tCheckPatC: " ++ show pp)
     () <- checkArity 0 pp
 --    xt <- derefUVar t
---    traceM ("tCheckPatC ds=" ++ show ds ++ "t=" ++ show xt)
+--    tcTrace ("tCheckPatC ds=" ++ show ds ++ "t=" ++ show xt)
     -- XXX must check for leaking skolems
     withDicts ds $
       ta pp
@@ -2076,7 +2078,7 @@
 
            | isConIdent i -> do
                (con, xpt) <- tLookupV i
---               traceM (show ipt)
+--               tcTrace (show ipt)
                case xpt of
                   -- Sanity check
                   EForall _ _ (EForall _ _ _) -> return ()
@@ -2112,9 +2114,9 @@
       | isNeg f -> lit       -- if it's (negate e) it must have been a negative literal
       | otherwise -> do
       ((skf, df, f'), ft) <- tInferPat f
---      traceM $ "tcPat: EApp f=" ++ showExpr f ++ "; e'=" ++ showExpr f' ++ " :: " ++ showEType ft
+--      tcTrace $ "tcPat: EApp f=" ++ showExpr f ++ "; e'=" ++ showExpr f' ++ " :: " ++ showEType ft
       (at, rt) <- unArrow loc ft
---      traceM ("tcPat EApp: " ++ showExpr f ++ " :: " ++ showEType ft)
+--      tcTrace ("tcPat EApp: " ++ showExpr f ++ " :: " ++ showEType ft)
       (ska, da, a') <- tCheckPat at a
       instPatSigma loc rt mt
       return (skf ++ ska, df ++ da, EApp f' a')
@@ -2370,7 +2372,7 @@
 checkSigma expr sigma = do
   (skol_tvs, rho) <- skolemise sigma
 --  sigma' <- derefUVar sigma
---  traceM $ "**** checkSigma: " ++ show expr ++ " :: " ++ show sigma ++ " = " ++ show sigma' ++ " " ++ show skol_tvs
+--  tcTrace $ "**** checkSigma: " ++ show expr ++ " :: " ++ show sigma ++ " = " ++ show sigma' ++ " " ++ show skol_tvs
   expr' <- tCheckExpr rho expr
   if null skol_tvs then
     -- Fast special case
@@ -2399,7 +2401,7 @@
   (a2,r2) <- unArrow loc rho2
   subsCheckFun loc exp1 a1 r1 a2 r2
 subsCheckRho loc exp1 tau1 tau2 = do  -- Rule MONO
---  traceM $ "subsCheckRho: MONO " ++ show (tau1, tau2)
+--  tcTrace $ "subsCheckRho: MONO " ++ show (tau1, tau2)
   unify loc tau1 tau2 -- Revert to ordinary unification
   return exp1
 
@@ -2412,11 +2414,11 @@
 instSigma :: HasCallStack =>
              SLoc -> Expr -> Sigma -> Expected -> T Expr
 instSigma loc e1 t1 (Check t2) = do
---  traceM ("instSigma: Check " ++ showEType t1 ++ " = " ++ showEType t2)
+--  tcTrace ("instSigma: Check " ++ showEType t1 ++ " = " ++ showEType t2)
   subsCheckRho loc e1 t1 t2
 instSigma loc e1 t1 (Infer r) = do
   (e1', t1') <- tInst e1 t1
-  --traceM ("instSigma: Infer " ++ showEType t1 ++ " ==> " ++ showEType t1')
+  --tcTrace ("instSigma: Infer " ++ showEType t1 ++ " ==> " ++ showEType t1')
   tSetRefType loc r t1'
   return e1'
 
@@ -2487,7 +2489,7 @@
   ds <- solveConstraints
   cs <- gets constraints
   vs <- getMetaTyVars (map snd cs)    -- These are the type variables that need defaulting
---  traceM $ "solveAndDefault: meta=" ++ show vs
+--  tcTrace $ "solveAndDefault: meta=" ++ show vs
   -- XXX may have to iterate this with fundeps
   ds' <- concat <$> mapM defaultOneTyVar vs
   return (a, ds ++ ds')
@@ -2506,10 +2508,11 @@
   let tryDefaults [] = return []
       tryDefaults (ty:tys) = do
         ok <- checkDefaultTypes ty ourcs
-        --traceM ("checkDefaultTypes: " ++ show (tv, ty, ourcs, ok))
+--        tcTrace ("checkDefaultTypes: " ++ show (EUVar tv, ty, ourcs, ok))
         if not ok then
           tryDefaults tys   -- don't default
          else do
+--          tcTrace $ "defaultOneTyVar: " ++ show (EUVar tv) ++ ":=" ++ showEType ty
           setUVar tv ty
           putConstraints ourcs
           ds <- solveConstraints
@@ -2516,10 +2519,12 @@
           rcs <- gets constraints
           if null rcs then do
             -- Success, the type variable is gone
+--            tcTrace $ "defaultOneTyVar success: " ++ show (EUVar tv)
             putConstraints othercs   -- put back the other constraints
             return ds
            else do
             -- Not solved, try with the nest type
+--            tcTrace $ "defaultOneTyVar failed: " ++ show rcs
             put old            -- restore solver state
             tryDefaults tys    -- and try with next type
   tryDefaults (defaults old)
@@ -2597,13 +2602,13 @@
     return []
    else do
     addMetaDicts
-    --traceM "------------------------------------------\nsolveConstraints"
+--    tcTrace "------------------------------------------\nsolveConstraints"
     cs' <- mapM (\ (i,t) -> do { t' <- derefUVar t; return (i,t') }) cs
-    --traceM ("constraints:\n" ++ unlines (map showConstraint cs'))
+--    tcTrace ("constraints:\n" ++ unlines (map showConstraint cs'))
     (unsolved, solved, improves) <- solveMany cs' [] [] []
     putConstraints unsolved
-    --traceM ("solved:\n"   ++ unlines [ showIdent i ++ " = "  ++ showExpr  e | (i, e) <- solved ])
-    --traceM ("unsolved:\n" ++ unlines [ showIdent i ++ " :: " ++ showEType t | (i, t) <- unsolved ])
+--    tcTrace ("solved:\n"   ++ unlines [ showIdent i ++ " = "  ++ showExpr  e | (i, e) <- solved ])
+--    tcTrace ("unsolved:\n" ++ unlines [ showIdent i ++ " :: " ++ showEType t | (i, t) <- unsolved ])
     if null improves then
       return solved
      else do
@@ -2624,7 +2629,7 @@
   [ (isJust . getTupleConstr,      solveTuple)        -- handle tuple constraints, i.e. (C1 t1, C2 t2, ...)
   , ((== mkIdent nameTypeEq),      solveTypeEq)       -- handle equality constraints, i.e. (t1 ~ t2)
   , ((== mkIdent nameKnownNat),    solveKnownNat)     -- KnownNat 999 constraints
-  , ((== mkIdent nameKnownSymbol), solveKnownSymbol)  -- KnownNat 999 constraints
+  , ((== mkIdent nameKnownSymbol), solveKnownSymbol)  -- KnownSymbol "abc" constraints
   , (const True,                   solveInst)         -- handle constraints with instances
   ]
 
@@ -2633,16 +2638,16 @@
 solveMany [] uns sol imp = return (uns, sol, imp)
 -- Need to handle ct of the form C => T, and forall a . T
 solveMany (cns@(di, ct) : cnss) uns sol imp = do
---  traceM ("trying " ++ showEType ct)
+--  tcTrace ("trying " ++ showEType ct)
   let loc = getSLoc di
       !(iCls, cts) = getApp ct
       solver = head [ s | (p, s) <- solvers, p iCls ]
   ads <- gets argDicts
   -- Check if we have an exact match among the arguments dictionaries.
-  -- This is importand to find tupled dictionaries in recursive calls.
+  -- This is important to find tupled dictionaries in recursive calls.
   case [ ai | (ai, act) <- ads, ct `eqEType` act ] of
     ai : _ -> do
-      --traceM $ "solve with arg " ++ show ct
+      --tcTrace $ "solve with arg " ++ show ct
       solveMany cnss uns ((di, EVar ai) : sol) imp
     [] -> do
       msol <- solver loc iCls cts
@@ -2653,10 +2658,11 @@
 solveInst :: SolveOne
 solveInst loc iCls cts = do
   it <- gets instTable
---  traceM ("instances:\n" ++ unlines (map showInstDef (M.toList it)))
+--  tcTrace ("instances:\n" ++ unlines (map showInstDef (M.toList it)))
   case M.lookup iCls it of
     Nothing -> return Nothing   -- no instances, so no chance
-    Just (InstInfo atomMap insts fds) ->
+    Just (InstInfo atomMap insts fds) -> do
+      -- tcTrace $ "solveInst: " ++ showIdent iCls ++ " atomMap size=" ++ show (M.size atomMap)
       case cts of
         [EVar i] -> do
           case M.lookup i atomMap of
@@ -2663,15 +2669,20 @@
             -- If the goal is just (C T) and there is an instance, the solution is simple
             Just e  -> return $ Just (e, [], [])
             -- Not found, but there might be a generic instance
-            Nothing -> solveGen fds insts loc iCls cts
-        _           -> solveGen fds insts loc iCls cts
+            Nothing -> solveGen (M.null atomMap) fds insts loc iCls cts
+        _           -> solveGen (M.null atomMap) fds insts loc iCls cts
 
-solveGen :: [IFunDep] -> [InstDict] -> SolveOne
-solveGen fds insts loc iCls cts = do
---  traceM ("solveGen " ++ show (iCls, cts))
-  let matches = getBestMatches $ findMatches loc fds insts cts
---  traceM ("matches " ++ showListS show (findMatches loc fds insts cts))
---  traceM ("matches " ++ showListS showMatch matches)
+-- When matching constraint (C _a) against an instance of the form
+-- instance (C b) then we don't want to match if the
+-- _a is later instantiated and it turns out we should
+-- have matched a (C T) instead.
+solveGen :: Bool -> [IFunDep] -> [InstDict] -> SolveOne
+solveGen noAtoms fds insts loc iCls cts = do
+--  tcTrace ("solveGen: " ++ show (iCls, cts))
+--  tcTrace ("solveGen: insts=" ++ show insts)
+  let matches = getBestMatches $ findMatches noAtoms loc fds insts cts
+--  tcTrace ("solveGen: matches allMatches =" ++ showListS show (findMatches noAtoms loc fds insts cts))
+--  tcTrace ("solveGen: matches bestMatches=" ++ showListS showMatch matches)
   case matches of
     []              -> return Nothing
     [(de, ctx, is)] ->
@@ -2679,7 +2690,7 @@
         return $ Just (de, [], is)
       else do
         d <- newDictIdent loc
---        traceM ("constraint " ++ showIdent di ++ " :: " ++ showEType ct ++ "\n" ++
+--        tcTrace ("constraint " ++ showIdent di ++ " :: " ++ showEType ct ++ "\n" ++
 --                "   turns into " ++ showIdent d ++ " :: " ++ showEType (tupleConstraints ctx) ++ ", " ++
 --                showIdent di ++ " = " ++ showExpr (EApp de (EVar d)))
         return $ Just (EApp de (EVar d), [(d, tupleConstraints ctx)], is)
@@ -2698,7 +2709,7 @@
 solveTypeEq loc _iCls [t1, t2] | isEUVar t1 || isEUVar t2 = return $ Just (ETuple [], [], [(loc, t1, t2)])
                                | otherwise = do
   eqs <- gets typeEqTable
-  --traceM ("solveTypeEq eqs=" ++ show eqs)
+  --tcTrace ("solveTypeEq eqs=" ++ show eqs)
   case solveEq eqs t1 t2 of
     Nothing -> return Nothing
     Just (de, tts) -> do
@@ -2733,8 +2744,9 @@
 -- For each matching instance return: (subst-size, (dict-expression, new-constraints))
 -- The subst-size is the size of the substitution that made the input instance match.
 -- It is a measure of how exact the match is.
-findMatches :: SLoc -> [IFunDep] -> [InstDict] -> [EType] -> [(Int, (Expr, [EConstraint], [Improve]))]
-findMatches loc fds ds its =
+findMatches :: Bool -> SLoc -> [IFunDep] -> [InstDict] -> [EType] -> [(Int, (Expr, [EConstraint], [Improve]))]
+findMatches False _ _ _ [EUVar _] = []
+findMatches _ loc fds ds its =
  let rrr =
        [ (length s, (de, map (substEUVar s) ctx, imp))
        | (de, ctx, ts) <- ds, Just (s, imp) <- [matchTypes loc ts its fds] ]
@@ -2776,7 +2788,7 @@
   -- We don't allow output FDs to have tyvars that are not instantiated
   let outImpTvs = metaTvs [ t | (_,t,_) <- imp ]
       outTvs = metaTvs [ t | (True, t) <- zip ins ts' ]   -- these tyvars were present in input positions in ts
---  traceM $ "matchTypesFD: " ++ show (ts, ts') ++ show (ins, outs) ++ show (tm, imp) ++ show (outTvs, outImpTvs)
+--  tcTrace $ "matchTypesFD: " ++ show (ts, ts') ++ show (ins, outs) ++ show (tm, imp) ++ show (outTvs, outImpTvs)
   when (not (null (outImpTvs \\ outTvs))) $
     errorMessage loc $ "free type variable in output fundep"
   pure (tm, imp)
@@ -2790,6 +2802,7 @@
     match r (EApp f a) (EApp f' a') = do
       r' <- match r f f'
       match r' a a'
+--    match _ _ (EUVar _) = Nothing
     match r (EUVar i) t' =
       -- For a variable, check that any previous match is the same.
       case lookup i r of
@@ -2833,7 +2846,7 @@
     (i, t) : _ -> do
       t' <- derefUVar t
 --      is <- gets instTable
---      traceM $ "Cannot satisfy constraint: " ++ unlines (map (\ (i, ii) -> show i ++ ":\n" ++ showInstInfo ii) (M.toList is))
+--      tcTrace $ "Cannot satisfy constraint: " ++ unlines (map (\ (i, ii) -> show i ++ ":\n" ++ showInstInfo ii) (M.toList is))
       tcError (getSLoc i) $ "Cannot satisfy constraint: " ++ show t'
 
 -- Add a type equality constraint.