lang: unification, interfaces: Add a skip invariant
This is a cleaner way of telling the type unifier that we don't want this particular expression in the solution set at the end.
This commit is contained in:
@@ -28,6 +28,8 @@ import (
|
|||||||
// Invariant represents a constraint that is described by the Expr's and Stmt's,
|
// Invariant represents a constraint that is described by the Expr's and Stmt's,
|
||||||
// and which is passed into the unification solver to describe what is known by
|
// and which is passed into the unification solver to describe what is known by
|
||||||
// the AST.
|
// the AST.
|
||||||
|
// XXX: add the extended methods into sub-interfaces since not each invariant
|
||||||
|
// uses them...
|
||||||
type Invariant interface {
|
type Invariant interface {
|
||||||
// TODO: should we add any other methods to this type?
|
// TODO: should we add any other methods to this type?
|
||||||
fmt.Stringer
|
fmt.Stringer
|
||||||
@@ -1049,3 +1051,34 @@ func (obj *CallFuncArgsValueInvariant) Possible(partials []Invariant) error {
|
|||||||
// XXX: not implemented
|
// XXX: not implemented
|
||||||
return nil // safer to return nil than error
|
return nil // safer to return nil than error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SkipInvariant expresses that a particular expression does must not be part of
|
||||||
|
// the final solution, and should be skipped. It can be part of the solving
|
||||||
|
// process though.
|
||||||
|
type SkipInvariant struct {
|
||||||
|
Expr Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a representation of this invariant.
|
||||||
|
func (obj *SkipInvariant) String() string {
|
||||||
|
return fmt.Sprintf("skip(%p)", obj.Expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExprList returns the list of valid expressions in this invariant. It is not
|
||||||
|
// used for this invariant.
|
||||||
|
func (obj *SkipInvariant) ExprList() []Expr {
|
||||||
|
// XXX: not used
|
||||||
|
return []Expr{obj.Expr}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matches is not used for this invariant.
|
||||||
|
func (obj *SkipInvariant) Matches(solved map[Expr]*types.Type) (bool, error) {
|
||||||
|
// XXX: not used
|
||||||
|
panic("not used")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Possible is not used for this invariant.
|
||||||
|
func (obj *SkipInvariant) Possible(partials []Invariant) error {
|
||||||
|
// XXX: not used
|
||||||
|
panic("not used")
|
||||||
|
}
|
||||||
|
|||||||
@@ -170,6 +170,9 @@ func DebugSolverState(solved map[interfaces.Expr]*types.Type, equalities []inter
|
|||||||
case *interfaces.AnyInvariant:
|
case *interfaces.AnyInvariant:
|
||||||
// skip, not used in the examples I care about
|
// skip, not used in the examples I care about
|
||||||
|
|
||||||
|
case *interfaces.SkipInvariant:
|
||||||
|
// we don't care about this one
|
||||||
|
|
||||||
default:
|
default:
|
||||||
s += fmt.Sprintf("%v\n", equality)
|
s += fmt.Sprintf("%v\n", equality)
|
||||||
}
|
}
|
||||||
@@ -249,6 +252,10 @@ func SimpleInvariantSolver(invariants []interfaces.Invariant, expected []interfa
|
|||||||
case *interfaces.CallFuncArgsValueInvariant:
|
case *interfaces.CallFuncArgsValueInvariant:
|
||||||
equalities = append(equalities, invariant)
|
equalities = append(equalities, invariant)
|
||||||
|
|
||||||
|
case *interfaces.SkipInvariant:
|
||||||
|
// drop it for now
|
||||||
|
//equalities = append(equalities, invariant)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, nil, fmt.Errorf("unknown invariant type: %T", x)
|
return nil, nil, fmt.Errorf("unknown invariant type: %T", x)
|
||||||
}
|
}
|
||||||
@@ -296,6 +303,8 @@ func SimpleInvariantSolver(invariants []interfaces.Invariant, expected []interfa
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//skipExprs := make(map[interfaces.Expr]struct{})
|
||||||
|
|
||||||
// XXX: if these partials all shared the same variable definition, would
|
// XXX: if these partials all shared the same variable definition, would
|
||||||
// it all work??? Maybe we don't even need the first map prefix...
|
// it all work??? Maybe we don't even need the first map prefix...
|
||||||
listPartials := make(map[interfaces.Expr]map[interfaces.Expr]*types.Type)
|
listPartials := make(map[interfaces.Expr]map[interfaces.Expr]*types.Type)
|
||||||
@@ -1074,6 +1083,11 @@ Loop:
|
|||||||
// a generator invariant wants to read them...
|
// a generator invariant wants to read them...
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
case *interfaces.SkipInvariant:
|
||||||
|
//skipExprs[eq.Expr] = struct{}{} // save
|
||||||
|
used = append(used, eqi) // mark equality as used up
|
||||||
|
continue
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown invariant type: %T", eqx)
|
return nil, fmt.Errorf("unknown invariant type: %T", eqx)
|
||||||
}
|
}
|
||||||
@@ -1334,6 +1348,12 @@ Loop:
|
|||||||
solutions := []*interfaces.EqualsInvariant{}
|
solutions := []*interfaces.EqualsInvariant{}
|
||||||
// FIXME: can we do this loop in a deterministic, sorted way?
|
// FIXME: can we do this loop in a deterministic, sorted way?
|
||||||
for expr, typ := range solved {
|
for expr, typ := range solved {
|
||||||
|
// Don't do this here, or the current Unifier struct machinery
|
||||||
|
// will see it as a bug. Do it there until we change the API.
|
||||||
|
//if _, exists := skipExprs[expr]; exists {
|
||||||
|
// continue
|
||||||
|
//}
|
||||||
|
|
||||||
invar := &interfaces.EqualsInvariant{
|
invar := &interfaces.EqualsInvariant{
|
||||||
Expr: expr,
|
Expr: expr,
|
||||||
Type: typ,
|
Type: typ,
|
||||||
|
|||||||
@@ -72,7 +72,13 @@ func (obj *Unifier) Unify() error {
|
|||||||
|
|
||||||
// build a list of what we think we need to solve for to succeed
|
// build a list of what we think we need to solve for to succeed
|
||||||
exprs := []interfaces.Expr{}
|
exprs := []interfaces.Expr{}
|
||||||
|
skips := make(map[interfaces.Expr]struct{})
|
||||||
for _, x := range invariants {
|
for _, x := range invariants {
|
||||||
|
if si, ok := x.(*interfaces.SkipInvariant); ok {
|
||||||
|
skips[si.Expr] = struct{}{}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
exprs = append(exprs, x.ExprList()...)
|
exprs = append(exprs, x.ExprList()...)
|
||||||
}
|
}
|
||||||
exprMap := ExprListToExprMap(exprs) // makes searching faster
|
exprMap := ExprListToExprMap(exprs) // makes searching faster
|
||||||
@@ -137,6 +143,10 @@ func (obj *Unifier) Unify() error {
|
|||||||
// programming error ?
|
// programming error ?
|
||||||
return fmt.Errorf("unexpected invalid solution at: %p", x)
|
return fmt.Errorf("unexpected invalid solution at: %p", x)
|
||||||
}
|
}
|
||||||
|
if _, exists := skips[x.Expr]; exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if obj.Debug {
|
if obj.Debug {
|
||||||
obj.Logf("solution: %p => %+v\t(%+v)", x.Expr, x.Type, x.Expr.String())
|
obj.Logf("solution: %p => %+v\t(%+v)", x.Expr, x.Type, x.Expr.String())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user