Check LHS arguments are polymorphic enough

We already did this, but missed a few cases due to the way arguments are
elaborated. So now, when checking an LHS, we don't allow LHS argument
types to be inferred from the pattern, but rather they must be inferred
from elsewhere. To do this, we keep track of the constraints which would
be solved when inferring the type, and make sure they don't solve any
new metavariables. Fixes #1510, and also now gets the error location
right as a bonus!
This commit is contained in:
Edwin Brady 2021-06-13 13:31:40 +01:00
parent 19cb2681be
commit 97ee3d4cd3
27 changed files with 220 additions and 73 deletions

View File

@ -141,7 +141,6 @@ isEmpty : {vars : _} ->
isEmpty defs env (NTCon fc n t a args) isEmpty defs env (NTCon fc n t a args)
= do Just nty <- lookupDefExact n (gamma defs) = do Just nty <- lookupDefExact n (gamma defs)
| _ => pure False | _ => pure False
log "coverage.empty" 10 $ "Checking type: " ++ show nty
case nty of case nty of
TCon _ _ _ _ flags _ cons _ TCon _ _ _ _ flags _ cons _
=> if not (external flags) => if not (external flags)

View File

@ -831,10 +831,11 @@ mutual
Core UnifyResult Core UnifyResult
solveHole loc mode env mname mref margs margs' locs submv solfull stm solnf solveHole loc mode env mname mref margs margs' locs submv solfull stm solnf
= do defs <- get Ctxt = do defs <- get Ctxt
ust <- get UST
empty <- clearDefs defs empty <- clearDefs defs
-- if the terms are the same, this isn't a solution -- if the terms are the same, this isn't a solution
-- but they are already unifying, so just return -- but they are already unifying, so just return
if solutionHeadSame solnf if solutionHeadSame solnf || inNoSolve mref (noSolve ust)
then pure success then pure success
else -- Rather than doing the occurs check here immediately, else -- Rather than doing the occurs check here immediately,
-- we'll wait until all metavariables are resolved, and in -- we'll wait until all metavariables are resolved, and in
@ -846,6 +847,12 @@ mutual
instantiate loc mode env mname mref (length margs) hdef locs solfull stm instantiate loc mode env mname mref (length margs) hdef locs solfull stm
pure $ solvedHole mref pure $ solvedHole mref
where where
inNoSolve : Int -> IntMap () -> Bool
inNoSolve i ns
= case lookup i ns of
Nothing => False
Just _ => True
-- Only need to check the head metavar is the same, we've already -- Only need to check the head metavar is the same, we've already
-- checked the rest if they are the same (and we couldn't instantiate it -- checked the rest if they are the same (and we couldn't instantiate it
-- anyway...) -- anyway...)

View File

@ -43,6 +43,18 @@ data Constraint : Type where
-- A resolved constraint -- A resolved constraint
Resolved : Constraint Resolved : Constraint
-- a constraint on the LHS arising from checking an argument in a position
-- where we expect a polymorphic type. If, in the end, the expected type is
-- polymorphic but the argument is concrete, then the pattern match is too
-- specific
public export
data PolyConstraint : Type where
MkPolyConstraint : {vars : _} ->
FC -> Env Term vars ->
(arg : Term vars) ->
(expty : NF vars) ->
(argty : NF vars) -> PolyConstraint
public export public export
record UState where record UState where
constructor MkUState constructor MkUState
@ -57,6 +69,12 @@ record UState where
-- user defined hole names, which don't need -- user defined hole names, which don't need
-- to have been solved -- to have been solved
constraints : IntMap Constraint -- map for finding constraints by ID constraints : IntMap Constraint -- map for finding constraints by ID
noSolve : IntMap () -- Names not to solve
-- If we're checking an LHS, then checking an argument can't
-- solve its own type, or we might end up with something
-- less polymorphic than it should be
polyConstraints : List PolyConstraint -- constraints which need to be solved
-- successfully to check an LHS is polymorphic enough
dotConstraints : List (Name, DotReason, Constraint) -- dot pattern constraints dotConstraints : List (Name, DotReason, Constraint) -- dot pattern constraints
nextName : Int nextName : Int
nextConstraint : Int nextConstraint : Int
@ -77,6 +95,8 @@ initUState = MkUState
, currentHoles = empty , currentHoles = empty
, delayedHoles = empty , delayedHoles = empty
, constraints = empty , constraints = empty
, noSolve = empty
, polyConstraints = []
, dotConstraints = [] , dotConstraints = []
, nextName = 0 , nextName = 0
, nextConstraint = 0 , nextConstraint = 0
@ -180,6 +200,20 @@ removeHoleName n
| Nothing => pure () | Nothing => pure ()
removeHole i removeHole i
export
addNoSolve : {auto u : Ref UST UState} ->
Int -> Core ()
addNoSolve i
= do ust <- get UST
put UST (record { noSolve $= insert i () } ust)
export
removeNoSolve : {auto u : Ref UST UState} ->
Int -> Core ()
removeNoSolve i
= do ust <- get UST
put UST (record { noSolve $= delete i } ust)
export export
saveHoles : {auto u : Ref UST UState} -> saveHoles : {auto u : Ref UST UState} ->
Core (IntMap (FC, Name)) Core (IntMap (FC, Name))
@ -281,6 +315,17 @@ addDot fc env dotarg x reason y
((dotarg, reason, MkConstraint fc False env xnf ynf) ::) ((dotarg, reason, MkConstraint fc False env xnf ynf) ::)
} ust) } ust)
export
addPolyConstraint : {vars : _} ->
{auto u : Ref UST UState} ->
FC -> Env Term vars -> Term vars -> NF vars -> NF vars ->
Core ()
addPolyConstraint fc env arg x@(NApp _ (NMeta _ _ _) _) y
= do ust <- get UST
put UST (record { polyConstraints $= ((MkPolyConstraint fc env arg x y) ::) } ust)
addPolyConstraint fc env arg x y
= pure ()
mkConstantAppArgs : {vars : _} -> mkConstantAppArgs : {vars : _} ->
Bool -> FC -> Env Term vars -> Bool -> FC -> Env Term vars ->
(wkns : List Name) -> (wkns : List Name) ->

View File

@ -428,7 +428,7 @@ perror (BadDotPattern fc env reason x y)
<++> parens (pretty reason) <+> dot) <+> line <+> !(ploc fc) <++> parens (pretty reason) <+> dot) <+> line <+> !(ploc fc)
perror (MatchTooSpecific fc env tm) perror (MatchTooSpecific fc env tm)
= pure $ errorDesc (reflow "Can't match on" <++> code !(pshow env tm) = pure $ errorDesc (reflow "Can't match on" <++> code !(pshow env tm)
<++> reflow "as it has a polymorphic type.") <+> line <+> !(ploc fc) <++> reflow "as it must have a polymorphic type.") <+> line <+> !(ploc fc)
perror (BadImplicit fc str) perror (BadImplicit fc str)
= pure $ errorDesc (reflow "Can't infer type for unbound implicit name" <++> code (pretty str) <+> dot) = pure $ errorDesc (reflow "Can't infer type for unbound implicit name" <++> code (pretty str) <+> dot)
<+> line <+> !(ploc fc) <+> line <+> reflow "Suggestion: try making it a bound implicit." <+> line <+> !(ploc fc) <+> line <+> reflow "Suggestion: try making it a bound implicit."

View File

@ -9,6 +9,7 @@ import Core.Metadata
import Core.Normalise import Core.Normalise
import Core.UnifyState import Core.UnifyState
import Core.Unify import Core.Unify
import Core.Value
import TTImp.Elab.Check import TTImp.Elab.Check
import TTImp.Elab.Delayed import TTImp.Elab.Delayed

View File

@ -383,7 +383,7 @@ checkAlternative rig elabinfo nest env fc (UniqueDefault def) alts mexpected
checkImp rig (addAmbig alts' (getName t) elabinfo) checkImp rig (addAmbig alts' (getName t) elabinfo)
nest env t nest env t
(Just exp'))) alts')) (Just exp'))) alts'))
(do log "elab" 5 "All failed, running default" (do log "elab.ambiguous" 5 "All failed, running default"
checkImp rig (addAmbig alts' (getName def) elabinfo) checkImp rig (addAmbig alts' (getName def) elabinfo)
nest env def (Just exp')) nest env def (Just exp'))
else exactlyOne' True fc env else exactlyOne' True fc env
@ -441,5 +441,5 @@ checkAlternative rig elabinfo nest env fc uniq alts mexpected
-- way that allows one pass) -- way that allows one pass)
solveConstraints solvemode Normal solveConstraints solvemode Normal
solveConstraints solvemode Normal solveConstraints solvemode Normal
log "elab" 10 $ show (getName t) ++ " success" log "elab.ambiguous" 10 $ show (getName t) ++ " success"
pure res)) alts') pure res)) alts')

View File

@ -153,18 +153,6 @@ isHole : NF vars -> Bool
isHole (NApp _ (NMeta _ _ _) _) = True isHole (NApp _ (NMeta _ _ _) _) = True
isHole _ = False isHole _ = False
-- Return whether we already know the return type of the given function
-- type. If we know this, we can possibly infer some argument types before
-- elaborating them, which might help us disambiguate things more easily.
concrete : Defs -> Env Term vars -> NF vars -> Core Bool
concrete defs env (NBind fc _ (Pi _ _ _ _) sc)
= do sc' <- sc defs (toClosure defaultOpts env (Erased fc False))
concrete defs env sc'
concrete defs env (NDCon _ _ _ _ _) = pure True
concrete defs env (NTCon _ _ _ _ _) = pure True
concrete defs env (NPrimVal _ _) = pure True
concrete defs env _ = pure False
mutual mutual
makeImplicit : {vars : _} -> makeImplicit : {vars : _} ->
{auto c : Ref Ctxt Defs} -> {auto c : Ref Ctxt Defs} ->
@ -324,9 +312,11 @@ mutual
needsDelayLHS (IAutoApp _ f _) = needsDelayLHS f needsDelayLHS (IAutoApp _ f _) = needsDelayLHS f
needsDelayLHS (INamedApp _ f _ _) = needsDelayLHS f needsDelayLHS (INamedApp _ f _ _) = needsDelayLHS f
needsDelayLHS (IAlternative _ _ _) = pure True needsDelayLHS (IAlternative _ _ _) = pure True
needsDelayLHS (IAs _ _ _ _ t) = needsDelayLHS t
needsDelayLHS (ISearch _ _) = pure True needsDelayLHS (ISearch _ _) = pure True
needsDelayLHS (IPrimVal _ _) = pure True needsDelayLHS (IPrimVal _ _) = pure True
needsDelayLHS (IType _) = pure True needsDelayLHS (IType _) = pure True
needsDelayLHS (IWithUnambigNames _ _ t) = needsDelayLHS t
needsDelayLHS _ = pure False needsDelayLHS _ = pure False
onLHS : ElabMode -> Bool onLHS : ElabMode -> Bool
@ -355,21 +345,6 @@ mutual
Bind _ _ (Lam _ _ _ _) _ => registerDot rig env fc NotConstructor tm ty Bind _ _ (Lam _ _ _ _) _ => registerDot rig env fc NotConstructor tm ty
_ => pure (tm, ty) _ => pure (tm, ty)
checkPatTyValid : {vars : _} ->
{auto c : Ref Ctxt Defs} ->
FC -> Defs -> Env Term vars ->
NF vars -> Term vars -> Glued vars -> Core ()
checkPatTyValid fc defs env (NApp _ (NMeta n i _) _) arg got
= do Just gdef <- lookupCtxtExact (Resolved i) (gamma defs)
| Nothing => pure ()
when (isErased (multiplicity gdef)) $ do
-- Argument is only valid if gotnf is not a concrete type
gotnf <- getNF got
when !(concrete defs env gotnf) $
throw (MatchTooSpecific fc env arg)
checkPatTyValid fc defs env _ _ _ = pure ()
dotErased : {auto c : Ref Ctxt Defs} -> (argty : NF vars) -> dotErased : {auto c : Ref Ctxt Defs} -> (argty : NF vars) ->
Maybe Name -> Nat -> ElabMode -> RigCount -> RawImp -> Core RawImp Maybe Name -> Nat -> ElabMode -> RigCount -> RawImp -> Core RawImp
dotErased argty mn argpos (InLHS lrig ) rig tm dotErased argty mn argpos (InLHS lrig ) rig tm
@ -462,12 +437,26 @@ mutual
aty' <- nf defs env metaty aty' <- nf defs env metaty
logNF "elab" 10 ("Now trying " ++ show nm ++ " " ++ show arg) env aty' logNF "elab" 10 ("Now trying " ++ show nm ++ " " ++ show arg) env aty'
res <- check argRig elabinfo nest env arg (Just $ glueBack defs env aty') -- On the LHS, checking an argument can't resolve its own type,
-- it must be resolved from elsewhere. Otherwise we might match
-- on things which are too specific for their polymorphic type.
when (onLHS (elabMode elabinfo)) $
case aty' of
NApp _ (NMeta _ i _) _ =>
do Just gdef <- lookupCtxtExact (Resolved i) (gamma defs)
| Nothing => pure ()
when (isErased (multiplicity gdef)) $ addNoSolve i
_ => pure ()
res <- check argRig (record { topLevel = False } elabinfo) nest env arg (Just $ glueBack defs env aty')
when (onLHS (elabMode elabinfo)) $
case aty' of
NApp _ (NMeta _ i _) _ => removeNoSolve i
_ => pure ()
(argv, argt) <- (argv, argt) <-
if not (onLHS (elabMode elabinfo)) if not (onLHS (elabMode elabinfo))
then pure res then pure res
else do let (argv, argt) = res else do let (argv, argt) = res
checkPatTyValid fc defs env aty' argv argt
checkValidPattern rig env fc argv argt checkValidPattern rig env fc argv argt
defs <- get Ctxt defs <- get Ctxt
@ -475,7 +464,7 @@ mutual
-- *may* have as patterns in it and we need to retain them. -- *may* have as patterns in it and we need to retain them.
-- (As patterns are a bit of a hack but I don't yet see a -- (As patterns are a bit of a hack but I don't yet see a
-- better way that leads to good code...) -- better way that leads to good code...)
logTerm "elab" 5 ("Solving " ++ show metaval ++ " with") argv logTerm "elab" 10 ("Solving " ++ show metaval ++ " with") argv
ok <- solveIfUndefined env metaval argv ok <- solveIfUndefined env metaval argv
-- If there's a constraint, make a constant, but otherwise -- If there's a constraint, make a constant, but otherwise
-- just return the term as expected -- just return the term as expected
@ -503,7 +492,7 @@ mutual
(\t => pure (Just !(toFullNames!(getTerm t)))) (\t => pure (Just !(toFullNames!(getTerm t))))
expty expty
pure ("Overall expected type: " ++ show ety)) pure ("Overall expected type: " ++ show ety))
res <- check argRig elabinfo res <- check argRig (record { topLevel = False } elabinfo)
nest env arg (Just (glueBack defs env aty)) nest env arg (Just (glueBack defs env aty))
(argv, argt) <- (argv, argt) <-
if not (onLHS (elabMode elabinfo)) if not (onLHS (elabMode elabinfo))

View File

@ -135,6 +135,10 @@ record EState (vars : List Name) where
allPatVars : List Name allPatVars : List Name
-- Holes standing for pattern variables, which we'll delete -- Holes standing for pattern variables, which we'll delete
-- once we're done elaborating -- once we're done elaborating
polyMetavars : List (FC, Env Term vars, Term vars, Term vars)
-- Metavars which need to be a polymorphic type at the end
-- of elaboration. If they aren't, it means we're trying to
-- pattern match on a type that we don't have available.
delayDepth : Nat -- if it gets too deep, it gets slow, so fail quicker delayDepth : Nat -- if it gets too deep, it gets slow, so fail quicker
linearUsed : List (Var vars) linearUsed : List (Var vars)
saveHoles : NameMap () -- things we'll need to save to TTC, even if solved saveHoles : NameMap () -- things we'll need to save to TTC, even if solved
@ -159,6 +163,7 @@ initEStateSub n env sub = MkEState
, bindIfUnsolved = [] , bindIfUnsolved = []
, lhsPatVars = [] , lhsPatVars = []
, allPatVars = [] , allPatVars = []
, polyMetavars = []
, delayDepth = Z , delayDepth = Z
, linearUsed = [] , linearUsed = []
, saveHoles = empty , saveHoles = empty
@ -187,6 +192,7 @@ weakenedEState {e}
, boundNames $= map wknTms , boundNames $= map wknTms
, toBind $= map wknTms , toBind $= map wknTms
, linearUsed $= map weaken , linearUsed $= map weaken
, polyMetavars = [] -- no binders on LHS
} est } est
pure eref pure eref
where where
@ -212,6 +218,7 @@ strengthenedEState {n} {vars} c e fc env
, boundNames = bns , boundNames = bns
, toBind = todo , toBind = todo
, linearUsed $= mapMaybe dropTop , linearUsed $= mapMaybe dropTop
, polyMetavars = [] -- no binders on LHS
} est } est
where where
@ -287,6 +294,28 @@ inScope {c} {e} fc env elab
put {ref=e} EST st' put {ref=e} EST st'
pure res pure res
export
mustBePoly : {auto e : Ref EST (EState vars)} ->
FC -> Env Term vars ->
Term vars -> Term vars -> Core ()
mustBePoly fc env tm ty
= do est <- get EST
put EST (record { polyMetavars $= ((fc, env, tm, ty) :: ) } est)
-- Return whether we already know the return type of the given function
-- type. If we know this, we can possibly infer some argument types before
-- elaborating them, which might help us disambiguate things more easily.
export
concrete : Defs -> Env Term vars -> NF vars -> Core Bool
concrete defs env (NBind fc _ (Pi _ _ _ _) sc)
= do sc' <- sc defs (toClosure defaultOpts env (Erased fc False))
concrete defs env sc'
concrete defs env (NDCon _ _ _ _ _) = pure True
concrete defs env (NTCon _ _ _ _ _) = pure True
concrete defs env (NPrimVal _ _) = pure True
concrete defs env (NType _) = pure True
concrete defs env _ = pure False
export export
updateEnv : {new : _} -> updateEnv : {new : _} ->
Env Term new -> SubVars new vars -> Env Term new -> SubVars new vars ->

View File

@ -70,6 +70,8 @@ delayOnFailure : {vars : _} ->
Core (Term vars, Glued vars) Core (Term vars, Glued vars)
delayOnFailure fc rig env expected pred pri elab delayOnFailure fc rig env expected pred pri elab
= do est <- get EST = do est <- get EST
ust <- get UST
let nos = noSolve ust -- remember the holes we shouldn't solve
handle (elab False) handle (elab False)
(\err => (\err =>
do est <- get EST do est <- get EST
@ -85,7 +87,15 @@ delayOnFailure fc rig env expected pred pri elab
defs <- get Ctxt defs <- get Ctxt
put UST (record { delayedElab $= put UST (record { delayedElab $=
((pri, ci, localHints defs, ((pri, ci, localHints defs,
mkClosedElab fc env (deeper (elab True))) :: ) } mkClosedElab fc env
(deeper
(do ust <- get UST
let nos' = noSolve ust
put UST (record { noSolve = nos } ust)
res <- elab True
ust <- get UST
put UST (record { noSolve = nos' } ust)
pure res))) :: ) }
ust) ust)
pure (dtm, expected) pure (dtm, expected)
else throw err) else throw err)
@ -103,6 +113,8 @@ delayElab : {vars : _} ->
Core (Term vars, Glued vars) Core (Term vars, Glued vars)
delayElab {vars} fc rig env exp pri elab delayElab {vars} fc rig env exp pri elab
= do est <- get EST = do est <- get EST
ust <- get UST
let nos = noSolve ust -- remember the holes we shouldn't solve
nm <- genName "delayed" nm <- genName "delayed"
expected <- mkExpected exp expected <- mkExpected exp
(ci, dtm) <- newDelayed fc linear env nm !(getTerm expected) (ci, dtm) <- newDelayed fc linear env nm !(getTerm expected)
@ -111,7 +123,14 @@ delayElab {vars} fc rig env exp pri elab
ust <- get UST ust <- get UST
defs <- get Ctxt defs <- get Ctxt
put UST (record { delayedElab $= put UST (record { delayedElab $=
((pri, ci, localHints defs, mkClosedElab fc env elab) :: ) } ((pri, ci, localHints defs, mkClosedElab fc env
(do ust <- get UST
let nos' = noSolve ust
put UST (record { noSolve = nos } ust)
res <- elab
ust <- get UST
put UST (record { noSolve = nos' } ust)
pure res)) :: ) }
ust) ust)
pure (dtm, expected) pure (dtm, expected)
where where

View File

@ -9,6 +9,7 @@ import Core.Env
import Core.Metadata import Core.Metadata
import Core.Normalise import Core.Normalise
import Core.Unify import Core.Unify
import Core.UnifyState
import Core.TT import Core.TT
import Core.Value import Core.Value
@ -473,6 +474,40 @@ checkBindVar rig elabinfo nest env fc str topexp
combine n l r = when (isIncompatible l r) combine n l r = when (isIncompatible l r)
(throw (LinearUsed fc 2 n)) (throw (LinearUsed fc 2 n))
checkPolyConstraint :
{auto c : Ref Ctxt Defs} ->
PolyConstraint -> Core ()
checkPolyConstraint (MkPolyConstraint fc env arg x y)
= do defs <- get Ctxt
-- If 'x' is a metavariable and 'y' is concrete, that means we've
-- ended up putting something too concrete in for a polymorphic
-- argument
xnf <- continueNF defs env x
case xnf of
NApp _ (NMeta _ _ _) _ =>
do ynf <- continueNF defs env y
if !(concrete defs env ynf)
then do empty <- clearDefs defs
throw (MatchTooSpecific fc env arg)
else pure ()
_ => pure ()
checkPolyConstraint _ = pure ()
solvePolyConstraint :
{auto c : Ref Ctxt Defs} ->
{auto u : Ref UST UState} ->
PolyConstraint -> Core ()
solvePolyConstraint (MkPolyConstraint fc env arg x y)
= do defs <- get Ctxt
-- If the LHS of the constraint isn't a metavariable, we can solve
-- the constraint
case !(continueNF defs env x) of
xnf@(NApp _ (NMeta _ _ _) _) => pure ()
t => do res <- unify inLHS fc env t !(continueNF defs env y)
-- If there's any constraints, it just means we didn't
-- solve anything and it won't help the check
pure ()
export export
checkBindHere : {vars : _} -> checkBindHere : {vars : _} ->
{auto c : Ref Ctxt Defs} -> {auto c : Ref Ctxt Defs} ->
@ -501,16 +536,26 @@ checkBindHere rig elabinfo nest env fc bindmode tm exp
solveConstraints (case elabMode elabinfo of solveConstraints (case elabMode elabinfo of
InLHS c => inLHS InLHS c => inLHS
_ => inTerm) Normal _ => inTerm) Normal
solveConstraintsAfter constart
(case elabMode elabinfo of
InLHS c => inLHS
_ => inTerm) Defaults
ust <- get UST ust <- get UST
catch (retryDelayed (delayedElab ust)) catch (retryDelayed (delayedElab ust))
(\err => (\err =>
do ust <- get UST do ust <- get UST
put UST (record { delayedElab = [] } ust) put UST (record { delayedElab = [] } ust)
throw err) throw err)
-- Check all the patterns standing for polymorphic variables are
-- indeed polymorphic
ust <- get UST
let cons = polyConstraints ust
put UST (record { polyConstraints = [] } ust)
traverse_ solvePolyConstraint cons
traverse_ checkPolyConstraint cons
solveConstraintsAfter constart
(case elabMode elabinfo of
InLHS c => inLHS
_ => inTerm) Defaults
checkDots -- Check dot patterns unifying with the claimed thing checkDots -- Check dot patterns unifying with the claimed thing
-- before binding names -- before binding names

View File

@ -295,6 +295,10 @@ TTImp.Elab.Check.check rigc elabinfo nest env tm_in exp
_ => do tm' <- insertImpLam env tm exp _ => do tm' <- insertImpLam env tm exp
checkImp rigc elabinfo nest env tm' exp checkImp rigc elabinfo nest env tm' exp
onLHS : ElabMode -> Bool
onLHS (InLHS _) = True
onLHS _ = False
-- As above, but doesn't add any implicit lambdas, forces, delays, etc -- As above, but doesn't add any implicit lambdas, forces, delays, etc
-- checkImp : {vars : _} -> -- checkImp : {vars : _} ->
-- {auto c : Ref Ctxt Defs} -> -- {auto c : Ref Ctxt Defs} ->
@ -304,4 +308,13 @@ TTImp.Elab.Check.check rigc elabinfo nest env tm_in exp
-- RigCount -> ElabInfo -> Env Term vars -> RawImp -> Maybe (Glued vars) -> -- RigCount -> ElabInfo -> Env Term vars -> RawImp -> Maybe (Glued vars) ->
-- Core (Term vars, Glued vars) -- Core (Term vars, Glued vars)
TTImp.Elab.Check.checkImp rigc elabinfo nest env tm exp TTImp.Elab.Check.checkImp rigc elabinfo nest env tm exp
= checkTerm rigc elabinfo nest env tm exp = do res <- checkTerm rigc elabinfo nest env tm exp
-- LHS arguments can't infer their own type - they need to be inferred
-- from some other argument. This is to prevent arguments being not
-- polymorphic enough. So, here, add the constraint to be checked later.
when (onLHS (elabMode elabinfo) && not (topLevel elabinfo)) $
do let (argv, argt) = res
let Just expty = exp
| Nothing => pure ()
addPolyConstraint (getFC tm) env argv !(getNF expty) !(getNF argt)
pure res

View File

@ -386,8 +386,8 @@ checkLHS {vars} trans mult hashit n opts nest env fc lhs_in
hasEmptyPat : {vars : _} -> hasEmptyPat : {vars : _} ->
{auto c : Ref Ctxt Defs} -> {auto c : Ref Ctxt Defs} ->
Defs -> Env Term vars -> Term vars -> Core Bool Defs -> Env Term vars -> Term vars -> Core Bool
hasEmptyPat defs env (Bind fc x b@(PVar _ _ _ ty) sc) hasEmptyPat defs env (Bind fc x b sc)
= pure $ !(isEmpty defs env !(nf defs env ty)) = pure $ !(isEmpty defs env !(nf defs env (binderType b)))
|| !(hasEmptyPat defs (b :: env) sc) || !(hasEmptyPat defs (b :: env) sc)
hasEmptyPat defs env _ = pure False hasEmptyPat defs env _ = pure False

View File

@ -122,7 +122,7 @@ idrisTestsRegression = MkTestPool "Various regressions" []
"reg015", "reg016", "reg017", "reg018", "reg019", "reg020", "reg021", "reg015", "reg016", "reg017", "reg018", "reg019", "reg020", "reg021",
"reg022", "reg023", "reg024", "reg025", "reg026", "reg027", "reg028", "reg022", "reg023", "reg024", "reg025", "reg026", "reg027", "reg028",
"reg029", "reg030", "reg031", "reg032", "reg033", "reg034", "reg035", "reg029", "reg030", "reg031", "reg032", "reg033", "reg034", "reg035",
"reg036", "reg037", "reg038", "reg039", "reg040"] "reg036", "reg037", "reg038", "reg039", "reg040", "reg041"]
idrisTestsData : TestPool idrisTestsData : TestPool
idrisTestsData = MkTestPool "Data and record types" [] idrisTestsData = MkTestPool "Data and record types" []

View File

@ -1,13 +1,13 @@
1/1: Building Cover (Cover.idr) 1/1: Building Cover (Cover.idr)
Error: While processing left hand side of badBar. Can't match on 0 as it has a polymorphic type. Error: While processing left hand side of badBar. Can't match on 0 as it must have a polymorphic type.
Cover:16:1--16:7 Cover:16:8--16:9
12 | cty Nat (S _) = S Z 12 | cty Nat (S _) = S Z
13 | cty _ x = S (S Z) 13 | cty _ x = S (S Z)
14 | 14 |
15 | badBar : a -> Nat 15 | badBar : a -> Nat
16 | badBar Z = Z 16 | badBar Z = Z
^^^^^^ ^
Main> Main.foo: foo (0, S _) Main> Main.foo: foo (0, S _)
foo (S _, _) foo (S _, _)

View File

@ -1,13 +1,13 @@
1/1: Building Cover (Cover.idr) 1/1: Building Cover (Cover.idr)
Error: While processing left hand side of bad. Can't match on Just (fromInteger 0) as it has a polymorphic type. Error: While processing left hand side of bad. Can't match on Just (fromInteger 0) as it must have a polymorphic type.
Cover:14:1--14:4 Cover:14:6--14:12
10 | 10 |
11 | bad : a -> Foo a -> Bool 11 | bad : a -> Foo a -> Bool
12 | bad Z IsNat = False 12 | bad Z IsNat = False
13 | bad True IsBool = True 13 | bad True IsBool = True
14 | bad (Just 0) _ = False 14 | bad (Just 0) _ = False
^^^ ^^^^^^
Main> Main.okay: okay (S _) IsNat Main> Main.okay: okay (S _) IsNat
okay False IsBool okay False IsBool

View File

@ -30,7 +30,7 @@ Issue1031-3:4:6--4:7
1/1: Building Issue1031-4 (Issue1031-4.idr) 1/1: Building Issue1031-4 (Issue1031-4.idr)
Error: While processing left hand side of nice. Unsolved holes: Error: While processing left hand side of nice. Unsolved holes:
Main.{dotTm:306} introduced at: Main.{dotTm:335} introduced at:
Issue1031-4:4:6--4:10 Issue1031-4:4:6--4:10
1 | %default total 1 | %default total
2 | 2 |

View File

@ -4,5 +4,5 @@ append {n = (S k)} (x :: xs) ys = ?foo_2
Main> vadd [] [] = ?bar_1 Main> vadd [] [] = ?bar_1
Main> vadd (x :: xs) (y :: ys) = ?baz_1 Main> vadd (x :: xs) (y :: ys) = ?baz_1
Main> suc x x Refl = ?quux_1 Main> suc x x Refl = ?quux_1
Main> suc' {x = y} {y = y} Refl = ?quuz_1 Main> suc' {x = x} {y = x} Refl = ?quuz_1
Main> Bye for now! Main> Bye for now!

View File

@ -4,5 +4,5 @@ Main> > append {n = 0} [] ys = ?foo_1
Main> > vadd [] [] = ?bar_1 Main> > vadd [] [] = ?bar_1
Main> > vadd (x :: xs) (y :: ys) = ?baz_1 Main> > vadd (x :: xs) (y :: ys) = ?baz_1
Main> > suc x x Refl = ?quux_1 Main> > suc x x Refl = ?quux_1
Main> > suc' {x = y} {y = y} Refl = ?quuz_1 Main> > suc' {x = x} {y = x} Refl = ?quuz_1
Main> Bye for now! Main> Bye for now!

View File

@ -4,5 +4,5 @@ append {n = (S k)} (x :: xs) ys = ?foo_2
Main> vadd [] [] = ?bar_1 Main> vadd [] [] = ?bar_1
Main> vadd (x :: xs) (y :: ys) = ?baz_1 Main> vadd (x :: xs) (y :: ys) = ?baz_1
Main> suc x x Refl = ?quux_1 Main> suc x x Refl = ?quux_1
Main> suc' {x = y} {y = y} Refl = ?quuz_1 Main> suc' {x = x} {y = x} Refl = ?quuz_1
Main> Bye for now! Main> Bye for now!

View File

@ -4,5 +4,5 @@ append {n = (S k)} (x :: xs) ys = ?foo_2
Main> vadd [] [] = ?bar_1 Main> vadd [] [] = ?bar_1
Main> vadd (x :: xs) (y :: ys) = ?baz_1 Main> vadd (x :: xs) (y :: ys) = ?baz_1
Main> suc x x Refl = ?quux_1 Main> suc x x Refl = ?quux_1
Main> suc' {x = y} {y = y} Refl = ?quuz_1 Main> suc' {x = x} {y = x} Refl = ?quuz_1
Main> Bye for now! Main> Bye for now!

View File

@ -207,7 +207,7 @@ namespace App1
export export
delay : {u : _} -> (1 k : App1 {u=u'} e b) -> delay : {u : _} -> (1 k : App1 {u=u'} e b) ->
Cont1Type u a u' e b Cont1Type u () u' e b
delay {u = One} mb = \ () => mb delay {u = One} mb = \ () => mb
delay {u = Any} mb = \ _ => mb delay {u = Any} mb = \ _ => mb

View File

@ -1,18 +1,18 @@
1/1: Building tuple (tuple.idr) 1/1: Building tuple (tuple.idr)
Error: While processing left hand side of tupleBug. Can't match on (?_, ?_) as it has a polymorphic type. Error: While processing left hand side of tupleBug. Can't match on (?_, ?_) as it must have a polymorphic type.
tuple:2:11--2:13 tuple:2:15--2:19
1 | tupleBug : Pair () a -> () 1 | tupleBug : Pair () a -> ()
2 | tupleBug (_, _, _) = () 2 | tupleBug (_, (_, _)) = ()
^^ ^^^^
Error: While processing left hand side of odd. Can't match on () as it has a polymorphic type. Error: While processing left hand side of odd. Can't match on () as it must have a polymorphic type.
tuple:5:1--5:4 tuple:5:5--5:7
1 | tupleBug : Pair () a -> () 1 | tupleBug : Pair () a -> ()
2 | tupleBug (_, _, _) = () 2 | tupleBug (_, (_, _)) = ()
3 | 3 |
4 | odd : a -> Bool 4 | odd : a -> Bool
5 | odd () = False 5 | odd () = False
^^^ ^^

View File

@ -1,5 +1,5 @@
tupleBug : Pair () a -> () tupleBug : Pair () a -> ()
tupleBug (_, _, _) = () tupleBug (_, (_, _)) = ()
odd : a -> Bool odd : a -> Bool
odd () = False odd () = False

View File

@ -2,10 +2,10 @@ Processing as TTImp
Written TTC Written TTC
Yaffle> Bye for now! Yaffle> Bye for now!
Processing as TTImp Processing as TTImp
Vect2:25:1--26:1:{pat 0 {b:27} : Type} => {pat 0 {a:26} : Type} => ($resolved379 {b:27}[1] {a:26}[0] $resolved361 ($resolved370 {a:26}[0]) ($resolved370 {b:27}[1])) is not a valid impossible pattern because it typechecks Vect2:25:1--26:1:{pat 0 {b:28} : Type} => {pat 0 {a:27} : Type} => ($resolved380 {b:28}[1] {a:27}[0] $resolved361 ($resolved370 {a:27}[0]) ($resolved370 {b:28}[1])) is not a valid impossible pattern because it typechecks
Yaffle> Bye for now! Yaffle> Bye for now!
Processing as TTImp Processing as TTImp
Vect3:25:1--26:1:Not a valid impossible pattern: Vect3:25:1--26:1:Not a valid impossible pattern:
Vect3:25:9--25:11:When unifying: Main.Nat and (Main.Vect ?Main.{n:21}_[] ?Main.{b:19}_[]) Vect3:25:9--25:11:When unifying: Main.Nat and (Main.Vect ?Main.{n:22}_[] ?Main.{b:20}_[])
Vect3:25:9--25:11:Type mismatch: Main.Nat and (Main.Vect ?Main.{n:21}_[] ?Main.{b:19}_[]) Vect3:25:9--25:11:Type mismatch: Main.Nat and (Main.Vect ?Main.{n:22}_[] ?Main.{b:20}_[])
Yaffle> Bye for now! Yaffle> Bye for now!

View File

@ -2,6 +2,6 @@ Processing as TTImp
Written TTC Written TTC
Yaffle> Main.lookup: All cases covered Yaffle> Main.lookup: All cases covered
Yaffle> Main.lookup': Yaffle> Main.lookup':
($resolved408 [__] [__] ($resolved376 [__]) {_:59}) ($resolved409 [__] [__] ($resolved377 [__]) {_:60})
Yaffle> Main.lookup'': Calls non covering function Main.lookup' Yaffle> Main.lookup'': Calls non covering function Main.lookup'
Yaffle> Bye for now! Yaffle> Bye for now!

View File

@ -1,5 +1,5 @@
Processing as TTImp Processing as TTImp
Written TTC Written TTC
Yaffle> ((Main.Refl [{b:9} = Main.Nat]) [x = (Main.S (Main.S (Main.S (Main.S Main.Z))))]) Yaffle> ((Main.Refl [{a:11} = Main.Nat]) [x = (Main.S (Main.S (Main.S (Main.S Main.Z))))])
Yaffle> Main.etaGood1 : ((((Main.Eq [b = (%pi RigW Explicit Nothing Integer (%pi RigW Explicit Nothing Integer Main.Test))]) [a = (%pi RigW Explicit Nothing Integer (%pi RigW Explicit Nothing Integer Main.Test))]) Main.MkTest) (%lam RigW Explicit (Just x) Integer (%lam RigW Explicit (Just y) Integer ((Main.MkTest x) y)))) Yaffle> Main.etaGood1 : ((((Main.Eq [b = (%pi RigW Explicit Nothing Integer (%pi RigW Explicit Nothing Integer Main.Test))]) [a = (%pi RigW Explicit Nothing Integer (%pi RigW Explicit Nothing Integer Main.Test))]) Main.MkTest) (%lam RigW Explicit (Just x) Integer (%lam RigW Explicit (Just y) Integer ((Main.MkTest x) y))))
Yaffle> Bye for now! Yaffle> Bye for now!

View File

@ -1,5 +1,5 @@
Processing as TTImp Processing as TTImp
Eta:16:1--17:1:When elaborating right hand side of Main.etaBad: Eta:16:1--17:1:When elaborating right hand side of Main.etaBad:
Eta:16:10--17:1:When unifying: (Main.Eq ({arg:10} : Integer) -> ({arg:11} : Integer) -> Main.Test)) ({arg:10} : Integer) -> ({arg:11} : Integer) -> Main.Test)) \(x : Char) => \(y : ?Main.{_:14}_[x[0]]) => (Main.MkTest x[1] y[0]) \(x : Char) => \(y : ?Main.{_:14}_[x[0]]) => (Main.MkTest x[1] y[0])) and (Main.Eq (x : Char) -> (y : ?Main.{_:14}_[x[0]]) -> Main.Test)) ({arg:10} : Integer) -> ({arg:11} : Integer) -> Main.Test)) Main.MkTest \(x : Char) => \(y : ?Main.{_:14}_[x[0]]) => (Main.MkTest x[1] y[0])) Eta:16:10--17:1:When unifying: (Main.Eq ({arg:12} : Integer) -> ({arg:13} : Integer) -> Main.Test)) ({arg:12} : Integer) -> ({arg:13} : Integer) -> Main.Test)) \(x : Char) => \(y : ?Main.{_:18}_[x[0]]) => (Main.MkTest x[1] y[0]) \(x : Char) => \(y : ?Main.{_:18}_[x[0]]) => (Main.MkTest x[1] y[0])) and (Main.Eq (x : Char) -> (y : ?Main.{_:18}_[x[0]]) -> Main.Test)) ({arg:12} : Integer) -> ({arg:13} : Integer) -> Main.Test)) Main.MkTest \(x : Char) => \(y : ?Main.{_:18}_[x[0]]) => (Main.MkTest x[1] y[0]))
Eta:16:10--17:1:Type mismatch: Integer and Char Eta:16:10--17:1:Type mismatch: Integer and Char
Yaffle> Bye for now! Yaffle> Bye for now!