getPartials is a helper function to aid in building partial types and values. Remember that it's not legal to run many of the normal methods like .String() on a partial type.
(fn *ExprFunc)
| 10876 | // Remember that it's not legal to run many of the normal methods like .String() |
| 10877 | // on a partial type. |
| 10878 | func (obj *ExprCall) getPartials(fn *ExprFunc) (*types.Type, []types.Value, error) { |
| 10879 | argGen := func(x int) (string, error) { |
| 10880 | // assume (incorrectly?) for now... |
| 10881 | return util.NumToAlpha(x), nil |
| 10882 | } |
| 10883 | if fn.Function != nil { |
| 10884 | namedArgsFn, ok := fn.function.(interfaces.NamedArgsFunc) // are the args named? |
| 10885 | if ok { |
| 10886 | argGen = namedArgsFn.ArgGen // func(int) string |
| 10887 | } |
| 10888 | } |
| 10889 | |
| 10890 | // build partial type and partial input values to aid in filtering... |
| 10891 | mapped := make(map[string]*types.Type) |
| 10892 | argNames := []string{} |
| 10893 | //partialValues := []types.Value{} |
| 10894 | partialValues := make([]types.Value, len(obj.Args)) |
| 10895 | for i, arg := range obj.Args { |
| 10896 | name, err := argGen(i) // get the Nth arg name |
| 10897 | if err != nil { |
| 10898 | return nil, nil, errwrap.Wrapf(err, "error getting arg #%d for func `%s`", i, obj.Name) |
| 10899 | } |
| 10900 | if name == "" { |
| 10901 | // possible programming error |
| 10902 | return nil, nil, fmt.Errorf("can't get arg #%d for func `%s`", i, obj.Name) |
| 10903 | } |
| 10904 | //mapped[name] = nil // unknown type |
| 10905 | argNames = append(argNames, name) |
| 10906 | //partialValues = append(partialValues, nil) // placeholder value |
| 10907 | |
| 10908 | // optimization: if type/value is already known, specify it now! |
| 10909 | var err1, err2 error |
| 10910 | // NOTE: This _can_ return unification variables now. Is it ok? |
| 10911 | mapped[name], err1 = arg.Type() // nil type on error |
| 10912 | partialValues[i], err2 = arg.Value() // nil value on error |
| 10913 | if err1 == nil && err2 == nil && mapped[name].Cmp(partialValues[i].Type()) != nil { |
| 10914 | // This can happen when we statically find an issue like |
| 10915 | // a printf scenario where it's wrong statically... |
| 10916 | t1 := mapped[name] |
| 10917 | t2 := partialValues[i].Type() |
| 10918 | return nil, nil, fmt.Errorf("type/value inconsistent at arg #%d for func `%s`: %v != %v", i, obj.Name, t1, t2) |
| 10919 | } |
| 10920 | } |
| 10921 | |
| 10922 | out, err := obj.Type() // do we know the return type yet? |
| 10923 | if err != nil { |
| 10924 | out = nil // just to make sure... |
| 10925 | } |
| 10926 | // partial type can have some type components that are nil! |
| 10927 | // this means they are not yet known at this time... |
| 10928 | partialType := &types.Type{ |
| 10929 | Kind: types.KindFunc, |
| 10930 | Map: mapped, |
| 10931 | Ord: argNames, |
| 10932 | Out: out, // possibly nil |
| 10933 | } |
| 10934 | |
| 10935 | return partialType, partialValues, nil |