@@ -159,13 +159,32 @@ private def isVariableTransition (p : Problem) : Bool :=
159159 | .var _ :: _ => true
160160 | _ => false
161161
162- private def isConstructorTransition (p : Problem) : Bool :=
163- (hasCtorPattern p || p.alts.isEmpty)
164- && p.alts.all fun alt => match alt.patterns with
165- | .ctor .. :: _ => true
166- | .var _ :: _ => true
167- | .inaccessible _ :: _ => true
168- | _ => false
162+ private def getInductiveVal? (x : Expr) : MetaM (Option InductiveVal) := do
163+ let xType ← inferType x
164+ let xType ← whnfD xType
165+ match xType.getAppFn with
166+ | Expr.const constName _ =>
167+ let cinfo ← getConstInfo constName
168+ match cinfo with
169+ | ConstantInfo.inductInfo val => return some val
170+ | _ => return none
171+ | _ => return none
172+
173+ def isCurrVarInductive (p : Problem) : MetaM Bool := do
174+ match p.vars with
175+ | [] => return false
176+ | x::_ => withGoalOf p do
177+ let val? ← getInductiveVal? x
178+ return val?.isSome
179+
180+ private def isConstructorTransition (p : Problem) : MetaM Bool := do
181+ return (← isCurrVarInductive p)
182+ && (hasCtorPattern p || p.alts.isEmpty)
183+ && p.alts.all fun alt => match alt.patterns with
184+ | .ctor .. :: _ => true
185+ | .var _ :: _ => true
186+ | .inaccessible _ :: _ => true
187+ | _ => false
169188
170189private def isValueTransition (p : Problem) : Bool :=
171190 hasVarPattern p && hasValPattern p
@@ -204,8 +223,7 @@ private def hasCtorOrInaccessible (p : Problem) : Bool :=
204223 | _ => false
205224
206225private def isNatValueTransition (p : Problem) : MetaM Bool := do
207- unless (← hasNatValPattern p) do return false
208- return hasCtorOrInaccessible p
226+ return (← hasNatValPattern p) && hasCtorOrInaccessible p
209227
210228/--
211229Predicate for testing whether we need to expand `Int` value patterns into constructors.
@@ -249,6 +267,10 @@ private def reorientCnstrs (alt : Alt) : Alt :=
249267/--
250268Remove constraints of the form `lhs ≋ rhs` where `lhs` and `rhs` are definitionally equal,
251269or `lhs` is a free variable.
270+
271+ Dropping unsolved constraints where `lhs` is a free variable seems unsound, but simply leads to later
272+ errors about the type of the alternative not matching the goal type, which is arguably a bit more
273+ user-friendly than showing possibly match-compilation-internal variable names.
252274-/
253275private def filterTrivialCnstrs (alt : Alt) : MetaM Alt := do
254276 let cnstrs ← withExistingLocalDecls alt.fvarDecls do
@@ -334,8 +356,9 @@ private def processAsPattern (p : Problem) : MetaM Problem := withGoalOf p do
334356 let alts ← p.alts.mapM fun alt => do
335357 match alt.patterns with
336358 | .as fvarId p h :: ps =>
337- /- We used to use `checkAndReplaceFVarId` here, but `x` and `fvarId` may have different types
338- when dependent types are being used. Let's consider the repro for issue #471
359+ /- We used to use eagerly check the types here (using what was called `checkAndReplaceFVarId`),
360+ but `x` and `fvarId` can have different types when dependent types are being used.
361+ Let's consider the repro for issue #471
339362 ```
340363 inductive vec : Nat → Type
341364 | nil : vec 0
@@ -409,11 +432,11 @@ alternative `cnstrs` field.
409432private def inLocalDecls (localDecls : List LocalDecl) (fvarId : FVarId) : Bool :=
410433 localDecls.any fun d => d.fvarId == fvarId
411434
412- private def expandVarIntoCtor? (alt : Alt) (ctorName : Name) : MetaM Alt := do
435+ private def expandVarIntoCtor (alt : Alt) (ctorName : Name) : MetaM Alt := do
413436 let .var fvarId :: ps := alt.patterns | unreachable!
414437 let alt := { alt with patterns := ps}
415438 withExistingLocalDecls alt.fvarDecls do
416- trace[Meta.Match.unify] "expandVarIntoCtor? fvarId: {mkFVar fvarId}, ctorName: {ctorName}, alt:\n {← alt.toMessageData}"
439+ trace[Meta.Match.unify] "expandVarIntoCtor fvarId: {mkFVar fvarId}, ctorName: {ctorName}, alt:\n {← alt.toMessageData}"
417440 let expectedType ← inferType (mkFVar fvarId)
418441 let expectedType ← whnfD expectedType
419442 let (ctorLevels, ctorParams) ← getInductiveUniverseAndParams expectedType
@@ -427,7 +450,7 @@ private def expandVarIntoCtor? (alt : Alt) (ctorName : Name) : MetaM Alt := do
427450 let mut cnstrs := alt.cnstrs
428451 unless (← isDefEqGuarded resultType expectedType) do
429452 cnstrs := (resultType, expectedType) :: cnstrs
430- trace[Meta.Match.unify] "expandVarIntoCtor? {mkFVar fvarId} : {expectedType}, ctor: {ctor}"
453+ trace[Meta.Match.unify] "expandVarIntoCtor {mkFVar fvarId} : {expectedType}, ctor: {ctor}"
431454 let ctorFieldPatterns := ctorFieldDecls.toList.map fun decl => Pattern.var decl.fvarId
432455 return { alt with fvarDecls := newAltDecls, patterns := ctorFieldPatterns ++ alt.patterns, cnstrs }
433456
@@ -443,46 +466,31 @@ private def expandInaccessibleIntoVar (alt : Alt) : MetaM Alt := do
443466 cnstrs := (x, e) :: alt.cnstrs
444467 }
445468
446- private def getInductiveVal? (x : Expr) : MetaM (Option InductiveVal) := do
447- let xType ← inferType x
448- let xType ← whnfD xType
449- match xType.getAppFn with
450- | Expr.const constName _ =>
451- let cinfo ← getConstInfo constName
452- match cinfo with
453- | ConstantInfo.inductInfo val => return some val
454- | _ => return none
455- | _ => return none
456-
457469private def hasRecursiveType (x : Expr) : MetaM Bool := do
458470 match (← getInductiveVal? x) with
459471 | some val => return val.isRec
460472 | _ => return false
461473
462474/-- Given `alt` s.t. the next pattern is an inaccessible pattern `e`,
463475 try to normalize `e` into a constructor application.
464- If it is not a constructor, throw an error.
465- Otherwise, if it is a constructor application of `ctorName`,
476+ If it is a constructor application of `ctorName`,
466477 update the next patterns with the fields of the constructor.
467478 Otherwise, move it to contraints, so that we fail unless some later step
468479 eliminates this alternative.
469480-/
470481def processInaccessibleAsCtor (alt : Alt) (ctorName : Name) : MetaM Alt := do
471- let p@( .inaccessible e) :: ps := alt.patterns | unreachable!
472- trace[Meta.Match.match] "inaccessible in ctor step {e}"
482+ let .inaccessible e :: ps := alt.patterns | unreachable!
483+ trace[Meta.Match.match] "inaccessible step {e} as ctor {ctorName }"
473484 withExistingLocalDecls alt.fvarDecls do
474485 -- Try to push inaccessible annotations.
475486 let e ← whnfD e
476- match (← constructorApp? e) with
477- | some (ctorVal, ctorArgs) =>
487+ if let some (ctorVal, ctorArgs) ← constructorApp? e then
478488 if ctorVal.name == ctorName then
479489 let fields := ctorArgs.extract ctorVal.numParams ctorArgs.size
480490 let fields := fields.toList.map .inaccessible
481491 return { alt with patterns := fields ++ ps }
482- else
483- let alt' ← expandInaccessibleIntoVar alt
484- expandVarIntoCtor? alt' ctorName
485- | _ => throwErrorAt alt.ref "Dependent match elimination failed: Expected a constructor, but found the inaccessible pattern{indentD p.toMessageData}"
492+ let alt' ← expandInaccessibleIntoVar alt
493+ expandVarIntoCtor alt' ctorName
486494
487495private def hasNonTrivialExample (p : Problem) : Bool :=
488496 p.examples.any fun | Example.underscore => false | _ => true
@@ -546,7 +554,7 @@ private def processConstructor (p : Problem) : MetaM (Array Problem) := do
546554 let newAlts ← newAlts.mapM fun alt => do
547555 match alt.patterns with
548556 | .ctor _ _ _ fields :: ps => return { alt with patterns := fields ++ ps }
549- | .var _ :: _ => expandVarIntoCtor? alt subgoal.ctorName
557+ | .var _ :: _ => expandVarIntoCtor alt subgoal.ctorName
550558 | .inaccessible _ :: _ => processInaccessibleAsCtor alt subgoal.ctorName
551559 | _ => unreachable!
552560 return { mvarId := subgoal.mvarId, vars := newVars, alts := newAlts, examples := examples }
@@ -563,7 +571,7 @@ private def processNonVariable (p : Problem) : MetaM Problem := withGoalOf p do
563571 else
564572 return some { alt with patterns := fields ++ ps }
565573 | .inaccessible _ :: _ => processInaccessibleAsCtor alt ctorVal.name
566- | .var _ :: _ => expandVarIntoCtor? alt ctorVal.name
574+ | .var _ :: _ => expandVarIntoCtor alt ctorVal.name
567575 | _ => unreachable!
568576 let xFields := xArgs.extract ctorVal.numParams xArgs.size
569577 return { p with alts := alts, vars := xFields.toList ++ xs }
@@ -724,13 +732,6 @@ private def throwNonSupported (p : Problem) : MetaM Unit :=
724732 let msg ← p.toMessageData
725733 throwError "Failed to compile pattern matching: Stuck at{indentD msg}"
726734
727- def isCurrVarInductive (p : Problem) : MetaM Bool := do
728- match p.vars with
729- | [] => return false
730- | x::_ => withGoalOf p do
731- let val? ← getInductiveVal? x
732- return val?.isSome
733-
734735private def checkNextPatternTypes (p : Problem) : MetaM Unit := do
735736 match p.vars with
736737 | [] => return ()
@@ -760,55 +761,79 @@ def processExFalso (p : Problem) : MetaM Problem := do
760761
761762private partial def process (p : Problem) : StateRefT State MetaM Unit := do
762763 traceState p
763- let isInductive ← isCurrVarInductive p
764764 if isDone p then
765765 traceStep ("leaf" )
766766 processLeaf p
767- else if (← isExFalsoTransition p) then
767+ return
768+
769+ if (← isExFalsoTransition p) then
768770 traceStep ("ex falso" )
769771 let p ← processExFalso p
770772 process p
771- else if hasAsPattern p then
773+ return
774+
775+ if hasAsPattern p then
772776 traceStep ("as-pattern" )
773777 let p ← processAsPattern p
774778 process p
775- else if (← isNatValueTransition p) then
779+ return
780+
781+ if (← isNatValueTransition p) then
776782 traceStep ("nat value to constructor" )
777783 process (← expandNatValuePattern p)
778- else if (← isIntValueTransition p) then
784+ return
785+
786+ if (← isIntValueTransition p) then
779787 traceStep ("int value to constructor" )
780788 process (← expandIntValuePattern p)
781- else if (← isFinValueTransition p) then
789+ return
790+
791+ if (← isFinValueTransition p) then
782792 traceStep ("fin value to constructor" )
783793 process (← expandFinValuePattern p)
784- else if (← isBitVecValueTransition p) then
794+ return
795+
796+ if (← isBitVecValueTransition p) then
785797 traceStep ("bitvec value to constructor" )
786798 process (← expandBitVecValuePattern p)
787- else if !isNextVar p then
799+ return
800+
801+ if !isNextVar p then
788802 traceStep ("non variable" )
789803 let p ← processNonVariable p
790804 process p
791- else if isInductive && isConstructorTransition p then
805+ return
806+
807+ if (← isConstructorTransition p) then
792808 let ps ← processConstructor p
793809 ps.forM process
794- else if isVariableTransition p then
810+ return
811+
812+ if isVariableTransition p then
795813 traceStep ("variable" )
796814 let p ← processVariable p
797815 process p
798- else if isValueTransition p then
816+ return
817+
818+ if isValueTransition p then
799819 let ps ← processValue p
800820 ps.forM process
801- else if isArrayLitTransition p then
821+ return
822+
823+ if isArrayLitTransition p then
802824 let ps ← processArrayLit p
803825 ps.forM process
804- else if (← hasNatValPattern p) then
826+ return
827+
828+ if (← hasNatValPattern p) then
805829 -- This branch is reachable when `p`, for example, is just values without an else-alternative.
806830 -- We added it just to get better error messages.
807831 traceStep ("nat value to constructor" )
808832 process (← expandNatValuePattern p)
809- else
810- checkNextPatternTypes p
811- throwNonSupported p
833+ return
834+
835+ checkNextPatternTypes p
836+ throwNonSupported p
812837
813838private def getUElimPos? (matcherLevels : List Level) (uElim : Level) : MetaM (Option Nat) :=
814839 if uElim == levelZero then
0 commit comments