Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Soundness violation around subtraction #76

Open
mniip opened this issue Sep 25, 2023 · 1 comment
Open

Soundness violation around subtraction #76

mniip opened this issue Sep 25, 2023 · 1 comment
Labels

Comments

@mniip
Copy link

mniip commented Sep 25, 2023

{- cabal:
build-depends: base, ghc-typelits-natnormalise
-}
{-# LANGUAGE AllowAmbiguousTypes, DataKinds, ExplicitForAll, TypeApplications, TypeFamilies, TypeOperators #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-}

import Data.Type.Equality
import GHC.TypeNats

urk :: False :~: True
urk = case sub @0 of Refl -> ineq @(0 - 1)
  where
    ineq :: forall k. (1 <=? 1 + k) :~: True
    ineq = Refl

    sub :: forall n m. (m ~ (n - 1)) => 1 + (n - 1) :~: n
    sub = Refl -- bogus

Note that the additional (redundant!) m type variable is necessary, without it the constraint is correctly rejected.

@christiaanb
Copy link
Member

So here's what's going on.

  1. In we remember that: whenever we see a - b, we must emit a b <= a constraint when we solve a constraint.
  2. Sometimes we find a "unifiers", such as the m ~ (n - 1), and them as substitution ([m := n - 1] when we follow the example), as we continue solving:
    Draw subst' -> do
    evM <- evMagic ct empty (map unifyItemToPredType subst' ++
    subToPred opts leqT k)
    let leqsG' | isGiven (ctEvidence ct) = eqToLeq u' v' ++ leqsG
    | otherwise = leqsG
    case evM of
    Nothing -> simples subst evs leqsG' xs eqs'
    Just ev ->
    simples (substsSubst subst' subst ++ subst')
    (ev:evs) leqsG' [] (xs ++ eqs')
  3. We apply these substitutions before we start solving equations:
    let u' = substsSOP subst u
    v' = substsSOP subst v
    ur <- unifyNats ct u' v'
  4. When we actually solve an equation we create a proof (in the form of a "BelieveMe"), but also emit any b <= a constraints we collected in step 1.
    Win -> do
    evs' <- maybe evs (:evs) <$> evMagic ct empty (subToPred opts leqT k)
    It's the subToPred opts leqT k part.
  5. The issue is that we do not carry over any b <= a constraints from step 2 to step 4. We only emit the b <= a constraints belonging to the constraint from before substitution we do in step 3.

So the solution is that whenever we create the substitution in step 2, we remember if we need to tag any b <= a constraints with them. And then in step 3, whenever a substitution carrying one of these constraints with them succeeds, we need to also emit those b <= a constraints in step 4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants