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:
@@ -97,10 +97,15 @@ func (obj *WrappedFunc) Validate() error {
|
||||
|
||||
// Info returns some static info about itself.
|
||||
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{
|
||||
Pure: true,
|
||||
Memo: false, // TODO: should this be something we specify here?
|
||||
Sig: obj.Fn.Type(),
|
||||
Sig: typ,
|
||||
Err: obj.Validate(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,14 +218,15 @@ func (obj *WrappedFunc) Validate() error {
|
||||
|
||||
// Info returns some static info about itself.
|
||||
func (obj *WrappedFunc) Info() *interfaces.Info {
|
||||
var sig *types.Type
|
||||
var typ *types.Type
|
||||
if obj.fn != nil { // don't panic if called speculatively
|
||||
sig = obj.fn.Type()
|
||||
typ = obj.fn.Type()
|
||||
}
|
||||
|
||||
return &interfaces.Info{
|
||||
Pure: true,
|
||||
Memo: false, // TODO: should this be something we specify here?
|
||||
Sig: sig,
|
||||
Sig: typ,
|
||||
Err: obj.Validate(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,23 +68,26 @@ func (obj *CallFunc) Validate() error {
|
||||
|
||||
// Info returns some static info about itself.
|
||||
func (obj *CallFunc) Info() *interfaces.Info {
|
||||
typ := &types.Type{
|
||||
Kind: types.KindFunc, // function type
|
||||
Map: make(map[string]*types.Type),
|
||||
Ord: []string{},
|
||||
Out: obj.Type, // this is the output type for the expression
|
||||
}
|
||||
var typ *types.Type
|
||||
if obj.Type != nil { // don't panic if called speculatively
|
||||
typ = &types.Type{
|
||||
Kind: types.KindFunc, // function type
|
||||
Map: make(map[string]*types.Type),
|
||||
Ord: []string{},
|
||||
Out: obj.Type, // this is the output type for the expression
|
||||
}
|
||||
|
||||
sig := obj.FuncType
|
||||
if obj.Edge != "" {
|
||||
typ.Map[obj.Edge] = sig // we get a function in
|
||||
typ.Ord = append(typ.Ord, obj.Edge)
|
||||
}
|
||||
sig := obj.FuncType
|
||||
if obj.Edge != "" {
|
||||
typ.Map[obj.Edge] = sig // we get a function in
|
||||
typ.Ord = append(typ.Ord, obj.Edge)
|
||||
}
|
||||
|
||||
// add any incoming args
|
||||
for _, key := range sig.Ord { // sig.Out, not sig!
|
||||
typ.Map[key] = sig.Map[key]
|
||||
typ.Ord = append(typ.Ord, key)
|
||||
// add any incoming args
|
||||
for _, key := range sig.Ord { // sig.Out, not sig!
|
||||
typ.Map[key] = sig.Map[key]
|
||||
typ.Ord = append(typ.Ord, key)
|
||||
}
|
||||
}
|
||||
|
||||
return &interfaces.Info{
|
||||
|
||||
@@ -42,10 +42,16 @@ func (obj *ConstFunc) Validate() error {
|
||||
|
||||
// Info returns some static info about itself.
|
||||
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{
|
||||
Pure: true,
|
||||
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!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,17 +82,20 @@ func (obj *FunctionFunc) Validate() error {
|
||||
|
||||
// Info returns some static info about itself.
|
||||
func (obj *FunctionFunc) Info() *interfaces.Info {
|
||||
typ := &types.Type{
|
||||
Kind: types.KindFunc, // function type
|
||||
Map: make(map[string]*types.Type),
|
||||
Ord: []string{},
|
||||
Out: obj.Type, // after the function is called it's this...
|
||||
}
|
||||
var typ *types.Type
|
||||
if obj.Type != nil { // don't panic if called speculatively
|
||||
typ = &types.Type{
|
||||
Kind: types.KindFunc, // function type
|
||||
Map: make(map[string]*types.Type),
|
||||
Ord: []string{},
|
||||
Out: obj.Type, // after the function is called it's this...
|
||||
}
|
||||
|
||||
// type of body is what we'd get by running the function (what's inside)
|
||||
if obj.Edge != "" {
|
||||
typ.Map[obj.Edge] = obj.Type.Out
|
||||
typ.Ord = append(typ.Ord, obj.Edge)
|
||||
// type of body is what we'd get by running the function (what's inside)
|
||||
if obj.Edge != "" {
|
||||
typ.Map[obj.Edge] = obj.Type.Out
|
||||
typ.Ord = append(typ.Ord, obj.Edge)
|
||||
}
|
||||
}
|
||||
|
||||
pure := true // assume true
|
||||
|
||||
@@ -46,15 +46,18 @@ func (obj *IfFunc) Validate() error {
|
||||
|
||||
// Info returns some static info about itself.
|
||||
func (obj *IfFunc) Info() *interfaces.Info {
|
||||
typ := &types.Type{
|
||||
Kind: types.KindFunc, // function type
|
||||
Map: map[string]*types.Type{
|
||||
"c": types.TypeBool, // conditional must be a boolean
|
||||
"a": obj.Type, // true branch must be this type
|
||||
"b": obj.Type, // false branch must be this type too
|
||||
},
|
||||
Ord: []string{"c", "a", "b"}, // conditional, and two branches
|
||||
Out: obj.Type, // result type must match
|
||||
var typ *types.Type
|
||||
if obj.Type != nil { // don't panic if called speculatively
|
||||
typ = &types.Type{
|
||||
Kind: types.KindFunc, // function type
|
||||
Map: map[string]*types.Type{
|
||||
"c": types.TypeBool, // conditional must be a boolean
|
||||
"a": obj.Type, // true branch must be this type
|
||||
"b": obj.Type, // false branch must be this type too
|
||||
},
|
||||
Ord: []string{"c", "a", "b"}, // conditional, and two branches
|
||||
Out: obj.Type, // result type must match
|
||||
}
|
||||
}
|
||||
|
||||
return &interfaces.Info{
|
||||
|
||||
@@ -52,11 +52,14 @@ func (obj *VarFunc) Validate() error {
|
||||
|
||||
// Info returns some static info about itself.
|
||||
func (obj *VarFunc) Info() *interfaces.Info {
|
||||
typ := &types.Type{
|
||||
Kind: types.KindFunc, // function type
|
||||
Map: map[string]*types.Type{obj.Edge: obj.Type},
|
||||
Ord: []string{obj.Edge},
|
||||
Out: obj.Type, // this is the output type for the expression
|
||||
var typ *types.Type
|
||||
if obj.Type != nil { // don't panic if called speculatively
|
||||
typ = &types.Type{
|
||||
Kind: types.KindFunc, // function type
|
||||
Map: map[string]*types.Type{obj.Edge: obj.Type},
|
||||
Ord: []string{obj.Edge},
|
||||
Out: obj.Type, // this is the output type for the expression
|
||||
}
|
||||
}
|
||||
|
||||
return &interfaces.Info{
|
||||
|
||||
Reference in New Issue
Block a user