diff --git a/src/go/types/testdata/slices.go2 b/src/go/types/testdata/slices.go2 new file mode 100644 index 0000000000..394a0652b6 --- /dev/null +++ b/src/go/types/testdata/slices.go2 @@ -0,0 +1,63 @@ +// Package slices implements various slice algorithms. +package slices + +// Map turns a []T1 to a []T2 using a mapping function. +func Map(type T1, T2)(s []T1, f func(T1) T2) []T2 { + r := make([]T2, len(s)) + for i, v := range s { + r[i] = f(v) + } + return r +} + +// Reduce reduces a []T1 to a single value using a reduction function. +func Reduce(type T1, T2)(s []T1, initializer T2, f func(T2, T1) T2) T2 { + r := initializer + for _, v := range s { + r = f(r, v) + } + return r +} + +// Filter filters values from a slice using a filter function. +func Filter(type T)(s []T, f func(T) bool) []T { + var r []T + for _, v := range s { + if f(v) { + r = append(r, v) + } + } + return r +} + +// Example uses + +func limiter(x int) byte { + switch { + case x < 0: + return 0 + default: + return byte(x) + case x > 255: + return 255 + } +} + +var input = []int{-4, 68954, 7, 44, 0, -555, 6945} +var limited1 = Map(int, byte)(input, limiter) +var limited2 = Map(input, limiter) // using type inference + +func reducer(x float64, y int) float64 { + return x + float64(y) +} + +var reduced1 = Reduce(int, float64)(input, 0, reducer) +var reduced2 = Reduce(input, 1.0, reducer) // using type inference + +func filter(x int) bool { + return x&1 != 0 +} + +var filtered1 = Filter(int)(input, filter) +var filtered2 = Filter(input, filter) // using type inference + diff --git a/src/go/types/testdata/tmp.go2 b/src/go/types/testdata/tmp.go2 index c37e9cc933..01df381fcb 100644 --- a/src/go/types/testdata/tmp.go2 +++ b/src/go/types/testdata/tmp.go2 @@ -1,8 +1,18 @@ package p -func Ranger(type T)() (*Receiver(T)) { - //return &Receiver(T){} // TODO(gri) make this work - return nil +func Reduce(type T1, T2)(s []T1, initializer T2, f func(T2, T1) T2) T2 { + r := initializer + for _, v := range s { + r = f(r, v) + } + return r } -type Receiver(type T) struct {} +func reducer(float64, int) float64 { + return 0 +} + +var _ = Reduce([]int{}, 1.0, reducer) + +// TODO(gri) investigate - seems like type inference should accept 1 here +// var _ = Reduce([]int{}, 1, reducer) diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index d5015c5b94..830854ab8c 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -143,10 +143,14 @@ func (check *Checker) definedType(e ast.Expr, def *Named) (T Type) { } // instantiatedType is like typ but it ensures that a Parametrized type is -// fully instantiated. +// fully instantiated if all type parameters are known. +// (When we type-check a parameterized function body, parameterized types +// whose type parameters are incoming parameters cannot be instantiated.) func (check *Checker) instantiatedType(e ast.Expr) Type { typ := check.typ(e) - if ptyp, _ := typ.(*Parameterized); ptyp != nil { + // A parameterized type where all type arguments are known + // (i.e., not type parameters themselves) can be instantiated. + if ptyp, _ := typ.(*Parameterized); ptyp != nil && !isParameterized(ptyp) { typ = check.inst(ptyp.tname, ptyp.targs) // TODO(gri) can this ever be nil? comment. if typ == nil {