-addConstraint t1 t2 = congruenceNewtypes t1 t2 >> unifyType t1 t2
-
--- A parallel fold over a Type value, replacing
--- in the right side reptypes for newtypes as found in the lhs
--- Sadly it doesn't cover all the possibilities. It does not always manage
--- to recover the highest level type. See test print016 for an example
-congruenceNewtypes :: TcType -> TcType -> TcM TcType
-congruenceNewtypes lhs rhs
--- | pprTrace "Congruence" (ppr lhs $$ ppr rhs) False = undefined
- -- We have a tctyvar at the other side
+addConstraint t1 t2 = congruenceNewtypes t1 t2 >>= uncurry unifyType
+
+{-
+ A parallel fold over two Type values,
+ compensating for missing newtypes on both sides.
+ This is necessary because newtypes are not present
+ in runtime, but since sometimes there is evidence
+ available we do our best to reconstruct them.
+ Evidence can come from DataCon signatures or
+ from compile-time type inference.
+ I am using the words congruence and rewriting
+ because what we are doing here is an approximation
+ of unification modulo a set of equations, which would
+ come from newtype definitions. These should be the
+ equality coercions seen in System Fc. Rewriting
+ is performed, taking those equations as rules,
+ before launching unification.
+
+ It doesn't make sense to rewrite everywhere,
+ or we would end up with all newtypes. So we rewrite
+ only in presence of evidence.
+ The lhs comes from the heap structure of ptrs,nptrs.
+ The rhs comes from a DataCon type signature.
+ Rewriting in the rhs is restricted to the result type.
+
+ Note that it is very tricky to make this 'rewriting'
+ work with the unification implemented by TcM, where
+ substitutions are 'inlined'. The order in which
+ constraints are unified is vital for this (or I am
+ using TcM wrongly).
+-}
+congruenceNewtypes :: TcType -> TcType -> TcM (TcType,TcType)
+congruenceNewtypes = go True
+ where
+ go rewriteRHS lhs rhs
+ -- TyVar lhs inductive case
+ | Just tv <- getTyVar_maybe lhs
+ = recoverM (return (lhs,rhs)) $ do
+ Indirect ty_v <- readMetaTyVar tv
+ (lhs', rhs') <- go rewriteRHS ty_v rhs
+ writeMutVar (metaTvRef tv) (Indirect lhs')
+ return (lhs, rhs')
+ -- TyVar rhs inductive case