Skip to content

Fix constraint cache and unexpected generalizations in BbML #305

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

Open
wants to merge 5 commits into
base: hkmc2
Choose a base branch
from

Conversation

NeilKleistGao
Copy link
Member

@NeilKleistGao NeilKleistGao commented May 2, 2025

Bugs found by @auht.

  • Some constraints cannot be correctly cached without .toBasic. Also improved type printing in error messages.
  • Fix unexpected generalizations.

Copy link
Contributor

@LPTK LPTK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we cache the Basic type (and not, say, the normalized one)? Can you explain what went wrong in the previous version?

@NeilKleistGao
Copy link
Member Author

Why do we cache the Basic type (and not, say, the normalized one)? Can you explain what went wrong in the previous version?

I think the real wrong place is here:

abstract class TypeExt extends Type:
  // ...
  override def equals(that: Any): Bool =
    toBasic === that

If the RHS is not a basic type, we cannot retrieve the constraint from the cache, leading to a stack overflow.

Here is the hash set dumped when we solve the constraint Conj(Inter(None),Union(None,List()),List((InfVar(1,99,hkmc2.bbml.VarState@62b2702b,false),true))) <: NegType(ComposedType(NegType(hkmc2.bbml.Bot$@14189e29),NegType(InfVar(1,103,hkmc2.bbml.VarState@662f0df5,false)),false)):

HashSet(
  (Conj(Inter(None),Union(None,List()),List((InfVar(1,97,hkmc2.bbml.VarState@6e9f9e57,false),true))),NegType(ComposedType(ClassLikeType(class:Cons1054›,List(Wildcard(hkmc2.bbml.Bot$@14189e29,NegType(hkmc2.bbml.Bot$@14189e29)), Wildcard(hkmc2.bbml.Bot$@14189e29,NegType(hkmc2.bbml.Bot$@14189e29)))),NegType(ComposedType(ClassLikeType(class:Cons1054›,List(Wildcard(InfVar(1,105,hkmc2.bbml.VarState@922ccdb,false),InfVar(1,106,hkmc2.bbml.VarState@4dcb19ef,false)), Wildcard(InfVar(1,107,hkmc2.bbml.VarState@606a2aed,false),InfVar(1,108,hkmc2.bbml.VarState@3349dd58,false)))),ClassLikeType(class:Nil1052›,List()),true)),false))),
  (InfVar(1,97,hkmc2.bbml.VarState@6e9f9e57,false),InfVar(1,103,hkmc2.bbml.VarState@662f0df5,false)),
  (Conj(Inter(None),Union(None,List()),List((InfVar(1,99,hkmc2.bbml.VarState@62b2702b,false),true))),NegType(ComposedType(ClassLikeType(class:Cons1054›,List(Wildcard(hkmc2.bbml.Bot$@14189e29,NegType(hkmc2.bbml.Bot$@14189e29)), Wildcard(hkmc2.bbml.Bot$@14189e29,NegType(hkmc2.bbml.Bot$@14189e29)))),NegType(ComposedType(ClassLikeType(class:Cons1054›,List(Wildcard(InfVar(1,105,hkmc2.bbml.VarState@922ccdb,false),InfVar(1,106,hkmc2.bbml.VarState@4dcb19ef,false)), Wildcard(InfVar(1,107,hkmc2.bbml.VarState@606a2aed,false),InfVar(1,108,hkmc2.bbml.VarState@3349dd58,false)))),ClassLikeType(class:Nil1052›,List()),true)),false))),
  (Conj(Inter(None),Union(None,List()),List((InfVar(1,99,hkmc2.bbml.VarState@62b2702b,false),true))),NegType(ComposedType(NegType(hkmc2.bbml.Bot$@14189e29),NegType(InfVar(1,103,hkmc2.bbml.VarState@662f0df5,false)),false))),
  (Conj(Inter(None),Union(None,List()),List((InfVar(1,97,hkmc2.bbml.VarState@6e9f9e57,false),true))),InfVar(1,103,hkmc2.bbml.VarState@662f0df5,false)),
  (Conj(Inter(None),Union(None,List()),List((InfVar(1,99,hkmc2.bbml.VarState@62b2702b,false),true))),InfVar(1,103,hkmc2.bbml.VarState@662f0df5,false)),
  (InfVar(1,99,hkmc2.bbml.VarState@62b2702b,false),NegType(Conj(Inter(Some(ClassLikeType(class:Cons1054›,List(Wildcard(Disj(List()),Disj(List(Conj(Inter(None),Union(None,List()),List())))), Wildcard(Disj(List()),Disj(List(Conj(Inter(None),Union(None,List()),List())))))))),Union(None,List(ClassLikeType(class:Cons1054›,List(Wildcard(InfVar(1,105,hkmc2.bbml.VarState@922ccdb,false),InfVar(1,106,hkmc2.bbml.VarState@4dcb19ef,false)), Wildcard(InfVar(1,107,hkmc2.bbml.VarState@606a2aed,false),InfVar(1,108,hkmc2.bbml.VarState@3349dd58,false)))), ClassLikeType(class:Nil1052›,List()))),List()))),
  (InfVar(1,97,hkmc2.bbml.VarState@6e9f9e57,false),NegType(Conj(Inter(Some(ClassLikeType(class:Cons1054›,List(Wildcard(Disj(List()),Disj(List(Conj(Inter(None),Union(None,List()),List())))), Wildcard(Disj(List()),Disj(List(Conj(Inter(None),Union(None,List()),List())))))))),Union(None,List(ClassLikeType(class:Cons1054›,List(Wildcard(InfVar(1,105,hkmc2.bbml.VarState@922ccdb,false),InfVar(1,106,hkmc2.bbml.VarState@4dcb19ef,false)), Wildcard(InfVar(1,107,hkmc2.bbml.VarState@606a2aed,false),InfVar(1,108,hkmc2.bbml.VarState@3349dd58,false)))), ClassLikeType(class:Nil1052›,List()))),List()))),
  (InfVar(1,97,hkmc2.bbml.VarState@6e9f9e57,false),NegType(Conj(Inter(Some(ClassLikeType(class:Cons1054›,List(Wildcard(Disj(List()),Disj(List(Conj(Inter(None),Union(None,List()),List())))), Wildcard(Disj(List()),Disj(List(Conj(Inter(None),Union(None,List()),List())))))))),Union(None,List(ClassLikeType(class:Cons1054›,List(Wildcard(InfVar(1,105,hkmc2.bbml.VarState@922ccdb,false),InfVar(1,106,hkmc2.bbml.VarState@4dcb19ef,false)), Wildcard(InfVar(1,107,hkmc2.bbml.VarState@606a2aed,false),InfVar(1,108,hkmc2.bbml.VarState@3349dd58,false)))), ClassLikeType(class:Nil1052›,List()))),List()))),
  (InfVar(1,97,hkmc2.bbml.VarState@6e9f9e57,false),NegType(Conj(Inter(Some(ClassLikeType(class:Cons1054›,List(Wildcard(Disj(List()),Disj(List(Conj(Inter(None),Union(None,List()),List())))), Wildcard(Disj(List()),Disj(List(Conj(Inter(None),Union(None,List()),List())))))))),Union(None,List(ClassLikeType(class:Cons1054›,List(Wildcard(InfVar(1,105,hkmc2.bbml.VarState@922ccdb,false),InfVar(1,106,hkmc2.bbml.VarState@4dcb19ef,false)), Wildcard(InfVar(1,107,hkmc2.bbml.VarState@606a2aed,false),InfVar(1,108,hkmc2.bbml.VarState@3349dd58,false)))), ClassLikeType(class:Nil1052›,List()))),List()))),
  (ComposedType(Disj(List(Conj(Inter(None),Union(None,List()),List((InfVar(1,99,hkmc2.bbml.VarState@62b2702b,false),true))))),Disj(List(Conj(Inter(None),Union(None,List()),List()))),false),InfVar(1,108,hkmc2.bbml.VarState@3349dd58,false)),
  (ComposedType(Disj(List(Conj(Inter(None),Union(None,List()),List((InfVar(1,99,hkmc2.bbml.VarState@62b2702b,false),true))))),Disj(List(Conj(Inter(None),Union(None,List()),List()))),false),InfVar(1,108,hkmc2.bbml.VarState@3349dd58,false)),
  (Conj(Inter(None),Union(None,List()),List((InfVar(1,99,hkmc2.bbml.VarState@62b2702b,false),true))),InfVar(1,108,hkmc2.bbml.VarState@3349dd58,false)),
  (Conj(Inter(None),Union(None,List()),List((InfVar(1,99,hkmc2.bbml.VarState@62b2702b,false),true))),InfVar(1,108,hkmc2.bbml.VarState@3349dd58,false)),
  (ClassLikeType(class:Cons1054›,List(InfVar(1,98,hkmc2.bbml.VarState@14f0f18b,false), InfVar(1,99,hkmc2.bbml.VarState@62b2702b,false))),NegType(Conj(Inter(Some(ClassLikeType(class:Cons1054›,List(Wildcard(Disj(List()),Disj(List(Conj(Inter(None),Union(None,List()),List())))), Wildcard(Disj(List()),Disj(List(Conj(Inter(None),Union(None,List()),List())))))))),Union(None,List(ClassLikeType(class:Cons1054›,List(Wildcard(InfVar(1,105,hkmc2.bbml.VarState@922ccdb,false),InfVar(1,106,hkmc2.bbml.VarState@4dcb19ef,false)), Wildcard(InfVar(1,107,hkmc2.bbml.VarState@606a2aed,false),InfVar(1,108,hkmc2.bbml.VarState@3349dd58,false)))), ClassLikeType(class:Nil1052›,List()))),List()))),
  (ClassLikeType(class:Cons1054›,List(InfVar(1,98,hkmc2.bbml.VarState@14f0f18b,false), InfVar(1,99,hkmc2.bbml.VarState@62b2702b,false))),NegType(Conj(Inter(Some(ClassLikeType(class:Cons1054›,List(Wildcard(Disj(List()),Disj(List(Conj(Inter(None),Union(None,List()),List())))), Wildcard(Disj(List()),Disj(List(Conj(Inter(None),Union(None,List()),List())))))))),Union(None,List(ClassLikeType(class:Cons1054›,List(Wildcard(InfVar(1,105,hkmc2.bbml.VarState@922ccdb,false),InfVar(1,106,hkmc2.bbml.VarState@4dcb19ef,false)), Wildcard(InfVar(1,107,hkmc2.bbml.VarState@606a2aed,false),InfVar(1,108,hkmc2.bbml.VarState@3349dd58,false)))), ClassLikeType(class:Nil1052›,List()))),List())))
)

I think we can cache normalized types, but we still need to remove this overridden equals. What do you think?

@LPTK
Copy link
Contributor

LPTK commented May 6, 2025

Oh yeah that equals looks really funky. Who added it and why? Let's cache things properly.

@NeilKleistGao NeilKleistGao changed the title Fix constraint cache in BbML Fix constraint cache and unexpected generalizations in BbML May 12, 2025
@@ -283,7 +284,8 @@ class BBTyper(using elState: Elaborator.State, tl: TL):
val funTy = tryMkMono(res, lam)
given CCtx = CCtx.init(lam, N)
constrain(funTy, funTyV)(using ctx)
pctx += sym -> PolyType.generalize(funTy, S(outer), 1)
if pctx.isTopLevel then // only generalize top-level definitions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need to go to such extreme? Normally the point of keeping track of levels is so that we can still generalize local functions. Is the root problem here that you forgot to increase the level of a function's definition when type checking it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, f is at a higher level, and the context level is increased in ctx.nestWithOuter. When type checking fun f(y) = x(y), we have y: 'y, x: 'x, and 'x <: 'y -> 'a for some fresh type variable 'a. After extrusion, x is typed to 'y0 -> 'a0, where 'y <: 'y0 and 'a0 <: 'a since 'y and 'a are not skolem. When type checking f(0), we instantiate 'y and 'a to fresh variables instead of continuing to constrain them because f is generalized. Therefore, x still has no bound.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of increasing the level if we're not going to generalize it? 🤔

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

Successfully merging this pull request may close these issues.

2 participants