lang: core: Fix struct lookup corner case

We forgot to reject this corner case which could lead to a runtime error
since the expected type from the incoming struct would not match what
we're handling.
This commit is contained in:
James Shubin
2025-01-26 18:46:44 -05:00
parent d46c43df5a
commit 3f202c6a7a
2 changed files with 52 additions and 1 deletions

View File

@@ -131,7 +131,7 @@ func (obj *StructLookupOptionalFunc) FuncInfer(partialType *types.Type, partialV
return nil, nil, fmt.Errorf("function must not have an empty field name")
}
// This can happen at runtime too, but we save it here for Build()!
//obj.field = s // don't store for this optional lookup version!
obj.field = s
// Figure out more about the sig if any information is known statically.
if len(partialType.Ord) > 0 && partialType.Map[partialType.Ord[0]] != nil {
@@ -200,6 +200,19 @@ func (obj *StructLookupOptionalFunc) Build(typ *types.Type) (*types.Type, error)
return nil, fmt.Errorf("first arg must be of kind struct, got: %s", tStruct.Kind)
}
if obj.field == "" {
// programming error
return nil, fmt.Errorf("got an empty field name")
}
// If the field exists, then it MUST match typ.Out of course!
tFoundField, exists := tStruct.Map[obj.field]
if exists {
if err := typ.Out.Cmp(tFoundField); err != nil {
return nil, errwrap.Wrapf(err, "non-optional arg must match return type")
}
}
obj.Type = tStruct // struct type
obj.Out = typ.Out // type of return value
obj.built = true
@@ -207,6 +220,20 @@ func (obj *StructLookupOptionalFunc) Build(typ *types.Type) (*types.Type, error)
return obj.sig(), nil
}
// Copy is implemented so that the obj.field value is not lost if we copy this
// function. That value is learned during FuncInfer, and previously would have
// been lost by the time we used it in Build.
func (obj *StructLookupOptionalFunc) Copy() interfaces.Func {
return &StructLookupOptionalFunc{
Type: obj.Type, // don't copy because we use this after unification
Out: obj.Out,
built: obj.built,
init: obj.init, // likely gets overwritten anyways
field: obj.field, // this we really need!
}
}
// Validate tells us if the input struct takes a valid form.
func (obj *StructLookupOptionalFunc) Validate() error {
if !obj.built {