lang: funcs: Ensure that Info sig's are invalid if not built yet

In case something in the type unification tries to speculatively call
Info before it's ready to produce a valid sig, make sure we only return
a definitive answer (non-nil, and no variant types) once we've
conclusively finished defining the signature.
This commit is contained in:
James Shubin
2021-05-19 10:33:35 -04:00
parent b3d1ed9e65
commit 95cfbd0fff
7 changed files with 68 additions and 44 deletions

View File

@@ -97,10 +97,15 @@ func (obj *WrappedFunc) Validate() error {
// Info returns some static info about itself. // Info returns some static info about itself.
func (obj *WrappedFunc) Info() *interfaces.Info { func (obj *WrappedFunc) Info() *interfaces.Info {
var typ *types.Type
if obj.Fn != nil { // don't panic if called speculatively
typ = obj.Fn.Type()
}
return &interfaces.Info{ return &interfaces.Info{
Pure: true, Pure: true,
Memo: false, // TODO: should this be something we specify here? Memo: false, // TODO: should this be something we specify here?
Sig: obj.Fn.Type(), Sig: typ,
Err: obj.Validate(), Err: obj.Validate(),
} }
} }

View File

@@ -218,14 +218,15 @@ func (obj *WrappedFunc) Validate() error {
// Info returns some static info about itself. // Info returns some static info about itself.
func (obj *WrappedFunc) Info() *interfaces.Info { func (obj *WrappedFunc) Info() *interfaces.Info {
var sig *types.Type var typ *types.Type
if obj.fn != nil { // don't panic if called speculatively if obj.fn != nil { // don't panic if called speculatively
sig = obj.fn.Type() typ = obj.fn.Type()
} }
return &interfaces.Info{ return &interfaces.Info{
Pure: true, Pure: true,
Memo: false, // TODO: should this be something we specify here? Memo: false, // TODO: should this be something we specify here?
Sig: sig, Sig: typ,
Err: obj.Validate(), Err: obj.Validate(),
} }
} }

View File

@@ -68,7 +68,9 @@ func (obj *CallFunc) Validate() error {
// Info returns some static info about itself. // Info returns some static info about itself.
func (obj *CallFunc) Info() *interfaces.Info { func (obj *CallFunc) Info() *interfaces.Info {
typ := &types.Type{ var typ *types.Type
if obj.Type != nil { // don't panic if called speculatively
typ = &types.Type{
Kind: types.KindFunc, // function type Kind: types.KindFunc, // function type
Map: make(map[string]*types.Type), Map: make(map[string]*types.Type),
Ord: []string{}, Ord: []string{},
@@ -86,6 +88,7 @@ func (obj *CallFunc) Info() *interfaces.Info {
typ.Map[key] = sig.Map[key] typ.Map[key] = sig.Map[key]
typ.Ord = append(typ.Ord, key) typ.Ord = append(typ.Ord, key)
} }
}
return &interfaces.Info{ return &interfaces.Info{
Pure: true, Pure: true,

View File

@@ -42,10 +42,16 @@ func (obj *ConstFunc) Validate() error {
// Info returns some static info about itself. // Info returns some static info about itself.
func (obj *ConstFunc) Info() *interfaces.Info { func (obj *ConstFunc) Info() *interfaces.Info {
var typ *types.Type
if obj.Value != nil { // don't panic if called speculatively
if t := obj.Value.Type(); t != nil {
typ = types.NewType(fmt.Sprintf("func() %s", t.String()))
}
}
return &interfaces.Info{ return &interfaces.Info{
Pure: true, Pure: true,
Memo: false, // TODO: ??? Memo: false, // TODO: ???
Sig: types.NewType(fmt.Sprintf("func() %s", obj.Value.Type().String())), Sig: typ,
Err: obj.Validate(), // XXX: implement this and check .Err in engine! Err: obj.Validate(), // XXX: implement this and check .Err in engine!
} }
} }

View File

@@ -82,7 +82,9 @@ func (obj *FunctionFunc) Validate() error {
// Info returns some static info about itself. // Info returns some static info about itself.
func (obj *FunctionFunc) Info() *interfaces.Info { func (obj *FunctionFunc) Info() *interfaces.Info {
typ := &types.Type{ var typ *types.Type
if obj.Type != nil { // don't panic if called speculatively
typ = &types.Type{
Kind: types.KindFunc, // function type Kind: types.KindFunc, // function type
Map: make(map[string]*types.Type), Map: make(map[string]*types.Type),
Ord: []string{}, Ord: []string{},
@@ -94,6 +96,7 @@ func (obj *FunctionFunc) Info() *interfaces.Info {
typ.Map[obj.Edge] = obj.Type.Out typ.Map[obj.Edge] = obj.Type.Out
typ.Ord = append(typ.Ord, obj.Edge) typ.Ord = append(typ.Ord, obj.Edge)
} }
}
pure := true // assume true pure := true // assume true
if obj.Func != nil { if obj.Func != nil {

View File

@@ -46,7 +46,9 @@ func (obj *IfFunc) Validate() error {
// Info returns some static info about itself. // Info returns some static info about itself.
func (obj *IfFunc) Info() *interfaces.Info { func (obj *IfFunc) Info() *interfaces.Info {
typ := &types.Type{ var typ *types.Type
if obj.Type != nil { // don't panic if called speculatively
typ = &types.Type{
Kind: types.KindFunc, // function type Kind: types.KindFunc, // function type
Map: map[string]*types.Type{ Map: map[string]*types.Type{
"c": types.TypeBool, // conditional must be a boolean "c": types.TypeBool, // conditional must be a boolean
@@ -56,6 +58,7 @@ func (obj *IfFunc) Info() *interfaces.Info {
Ord: []string{"c", "a", "b"}, // conditional, and two branches Ord: []string{"c", "a", "b"}, // conditional, and two branches
Out: obj.Type, // result type must match Out: obj.Type, // result type must match
} }
}
return &interfaces.Info{ return &interfaces.Info{
Pure: true, Pure: true,

View File

@@ -52,12 +52,15 @@ func (obj *VarFunc) Validate() error {
// Info returns some static info about itself. // Info returns some static info about itself.
func (obj *VarFunc) Info() *interfaces.Info { func (obj *VarFunc) Info() *interfaces.Info {
typ := &types.Type{ var typ *types.Type
if obj.Type != nil { // don't panic if called speculatively
typ = &types.Type{
Kind: types.KindFunc, // function type Kind: types.KindFunc, // function type
Map: map[string]*types.Type{obj.Edge: obj.Type}, Map: map[string]*types.Type{obj.Edge: obj.Type},
Ord: []string{obj.Edge}, Ord: []string{obj.Edge},
Out: obj.Type, // this is the output type for the expression Out: obj.Type, // this is the output type for the expression
} }
}
return &interfaces.Info{ return &interfaces.Info{
Pure: true, Pure: true,