diff options
author | Dmitri Shuralyov <dmitshur@google.com> | 2022-08-01 15:53:43 +0000 |
---|---|---|
committer | Dmitri Shuralyov <dmitshur@google.com> | 2022-08-01 15:53:43 +0000 |
commit | 270c7b73de4ab3680b3ee977568888c272431619 (patch) | |
tree | e5b4297f208e42d8eb3c9f654817a397bda91ae1 | |
parent | 913e3713bed373f85c7cdb933d3714dd587e685e (diff) | |
parent | be59153dd8e67d83428e18a44dd29df3059c21fe (diff) | |
download | go-git-270c7b73de4ab3680b3ee977568888c272431619.tar.gz |
[dev.boringcrypto.go1.18] all: merge go1.18.5 into dev.boringcrypto.go1.18
Change-Id: I96f4685336746989b39b570816f595fab0b751fe
-rw-r--r-- | src/cmd/compile/internal/noder/stencil.go | 4 | ||||
-rw-r--r-- | src/cmd/compile/internal/typecheck/stmt.go | 18 | ||||
-rw-r--r-- | src/cmd/compile/internal/walk/complit.go | 8 | ||||
-rw-r--r-- | src/cmd/go/internal/load/pkg.go | 21 | ||||
-rw-r--r-- | src/cmd/go/internal/modload/buildlist.go | 5 | ||||
-rw-r--r-- | src/cmd/go/testdata/script/version_build_settings.txt | 17 | ||||
-rw-r--r-- | src/cmd/go/testdata/script/work_goproxy_off.txt | 59 | ||||
-rw-r--r-- | src/math/big/floatmarsh.go | 7 | ||||
-rw-r--r-- | src/math/big/floatmarsh_test.go | 12 | ||||
-rw-r--r-- | src/math/big/ratmarsh.go | 6 | ||||
-rw-r--r-- | src/math/big/ratmarsh_test.go | 12 | ||||
-rw-r--r-- | src/runtime/time.go | 12 | ||||
-rw-r--r-- | src/runtime/traceback.go | 15 | ||||
-rw-r--r-- | src/testing/testing.go | 2 | ||||
-rw-r--r-- | src/testing/testing_other.go | 6 | ||||
-rw-r--r-- | src/testing/testing_windows.go | 22 | ||||
-rw-r--r-- | test/fixedbugs/issue52953.go | 29 | ||||
-rw-r--r-- | test/typeparam/issue51840.go | 36 | ||||
-rw-r--r-- | test/typeparam/issue53309.go | 42 |
19 files changed, 220 insertions, 113 deletions
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index e89b69284c..a41b35a0dd 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1297,10 +1297,10 @@ func (g *genInst) dictPass(info *instInfo) { m = convertUsingDictionary(info, info.dictParam, m.Pos(), mce.X, m, m.Type(), false) } case ir.ODOTTYPE, ir.ODOTTYPE2: - dt := m.(*ir.TypeAssertExpr) - if !dt.Type().HasShape() && !dt.X.Type().HasShape() { + if !m.Type().HasShape() { break } + dt := m.(*ir.TypeAssertExpr) var rt ir.Node if dt.Type().IsInterface() || dt.X.Type().IsEmptyInterface() { ix := findDictType(info, m.Type()) diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go index 7ab9a1df96..9a02c1752c 100644 --- a/src/cmd/compile/internal/typecheck/stmt.go +++ b/src/cmd/compile/internal/typecheck/stmt.go @@ -127,23 +127,13 @@ func assign(stmt ir.Node, lhs, rhs []ir.Node) { checkLHS := func(i int, typ *types.Type) { lhs[i] = Resolve(lhs[i]) - if base.Flag.G != 0 || base.Debug.Unified != 0 { - // New logic added in CL 403837 for Go 1.19, which only has -G=3 and unified IR. - if n := lhs[i]; typ != nil && ir.DeclaredBy(n, stmt) && n.Type() == nil { - base.Assertf(typ.Kind() == types.TNIL, "unexpected untyped nil") + if n := lhs[i]; typ != nil && ir.DeclaredBy(n, stmt) && n.Name().Ntype == nil { + if typ.Kind() != types.TNIL { n.SetType(defaultType(typ)) - } - } else { - // Original logic from Go 1.18, which is still needed for -G=0. - if n := lhs[i]; typ != nil && ir.DeclaredBy(n, stmt) && n.Name().Ntype == nil { - if typ.Kind() != types.TNIL { - n.SetType(defaultType(typ)) - } else { - base.Errorf("use of untyped nil") - } + } else { + base.Errorf("use of untyped nil") } } - if lhs[i].Typecheck() == 0 { lhs[i] = AssignExpr(lhs[i]) } diff --git a/src/cmd/compile/internal/walk/complit.go b/src/cmd/compile/internal/walk/complit.go index b985b4caeb..e957580071 100644 --- a/src/cmd/compile/internal/walk/complit.go +++ b/src/cmd/compile/internal/walk/complit.go @@ -621,6 +621,12 @@ func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool { // not a special composite literal assignment return false } + if x.Addrtaken() { + // If x is address-taken, the RHS may (implicitly) uses LHS. + // Not safe to do a special composite literal assignment + // (which may expand to multiple assignments). + return false + } switch n.Y.Op() { default: @@ -629,7 +635,7 @@ func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool { case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT: if ir.Any(n.Y, func(y ir.Node) bool { return ir.Uses(y, x) }) { - // not a special composite literal assignment + // not safe to do a special composite literal assignment if RHS uses LHS. return false } anylit(n.Y, n.X, init) diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 94bcf89e10..a8137cc65e 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -2335,7 +2335,17 @@ func (p *Package) setBuildInfo(includeVCS bool) { appendSetting("-gcflags", BuildGcflags.String()) } if BuildLdflags.present { - appendSetting("-ldflags", BuildLdflags.String()) + // https://go.dev/issue/52372: only include ldflags if -trimpath is not set, + // since it can include system paths through various linker flags (notably + // -extar, -extld, and -extldflags). + // + // TODO: since we control cmd/link, in theory we can parse ldflags to + // determine whether they may refer to system paths. If we do that, we can + // redact only those paths from the recorded -ldflags setting and still + // record the system-independent parts of the flags. + if !cfg.BuildTrimpath { + appendSetting("-ldflags", BuildLdflags.String()) + } } if cfg.BuildMSan { appendSetting("-msan", "true") @@ -2351,7 +2361,14 @@ func (p *Package) setBuildInfo(includeVCS bool) { cgo = "1" } appendSetting("CGO_ENABLED", cgo) - if cfg.BuildContext.CgoEnabled { + // https://go.dev/issue/52372: only include CGO flags if -trimpath is not set. + // (If -trimpath is set, it is possible that these flags include system paths.) + // If cgo is involved, reproducibility is already pretty well ruined anyway, + // given that we aren't stamping header or library versions. + // + // TODO(bcmills): perhaps we could at least parse the flags and stamp the + // subset of flags that are known not to be paths? + if cfg.BuildContext.CgoEnabled && !cfg.BuildTrimpath { for _, name := range []string{"CGO_CFLAGS", "CGO_CPPFLAGS", "CGO_CXXFLAGS", "CGO_LDFLAGS"} { appendSetting(name, cfg.Getenv(name)) } diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go index 6f9072c8c4..0664dd43eb 100644 --- a/src/cmd/go/internal/modload/buildlist.go +++ b/src/cmd/go/internal/modload/buildlist.go @@ -397,7 +397,6 @@ func readModGraph(ctx context.Context, pruning modPruning, roots []module.Versio seen := map[module.Version]bool{} for _, m := range roots { hasDepsInAll[m.Path] = true - seen[m] = true } // This loop will terminate because it will call enqueue on each version of // each dependency of the modules in hasDepsInAll at most once (and only @@ -406,11 +405,11 @@ func readModGraph(ctx context.Context, pruning modPruning, roots []module.Versio needsEnqueueing := map[module.Version]bool{} for p := range hasDepsInAll { m := module.Version{Path: p, Version: mg.g.Selected(p)} - reqs, ok := mg.g.RequiredBy(m) - if !ok { + if !seen[m] { needsEnqueueing[m] = true continue } + reqs, _ := mg.g.RequiredBy(m) for _, r := range reqs { s := module.Version{Path: r.Path, Version: mg.g.Selected(r.Path)} if cmpVersion(s.Version, r.Version) > 0 && !seen[s] { diff --git a/src/cmd/go/testdata/script/version_build_settings.txt b/src/cmd/go/testdata/script/version_build_settings.txt index dc9e67681e..08df7e611d 100644 --- a/src/cmd/go/testdata/script/version_build_settings.txt +++ b/src/cmd/go/testdata/script/version_build_settings.txt @@ -47,19 +47,34 @@ go build go version -m m$GOEXE stdout '^\tbuild\tCGO_ENABLED=0$' ! stdout CGO_CPPFLAGS|CGO_CFLAGS|CGO_CXXFLAGS|CGO_LDFLAGS + [cgo] env CGO_ENABLED=1 [cgo] env CGO_CPPFLAGS=-DFROM_CPPFLAGS=1 [cgo] env CGO_CFLAGS=-DFROM_CFLAGS=1 [cgo] env CGO_CXXFLAGS=-DFROM_CXXFLAGS=1 [cgo] env CGO_LDFLAGS=-L/extra/dir/does/not/exist -[cgo] go build +[cgo] go build '-ldflags=all=-linkmode=external -extldflags=-L/bonus/dir/does/not/exist' [cgo] go version -m m$GOEXE +[cgo] stdout '^\tbuild\t-ldflags="all=-linkmode=external -extldflags=-L/bonus/dir/does/not/exist"$' [cgo] stdout '^\tbuild\tCGO_ENABLED=1$' [cgo] stdout '^\tbuild\tCGO_CPPFLAGS=-DFROM_CPPFLAGS=1$' [cgo] stdout '^\tbuild\tCGO_CFLAGS=-DFROM_CFLAGS=1$' [cgo] stdout '^\tbuild\tCGO_CXXFLAGS=-DFROM_CXXFLAGS=1$' [cgo] stdout '^\tbuild\tCGO_LDFLAGS=-L/extra/dir/does/not/exist$' +# https://go.dev/issue/52372: a cgo-enabled binary should not be stamped with +# CGO_ flags that contain paths. +[cgo] env CGO_ENABLED=1 +[cgo] env CGO_CPPFLAGS=-DFROM_CPPFLAGS=1 +[cgo] env CGO_CFLAGS=-DFROM_CFLAGS=1 +[cgo] env CGO_CXXFLAGS=-DFROM_CXXFLAGS=1 +[cgo] env CGO_LDFLAGS=-L/extra/dir/does/not/exist +[cgo] go build -trimpath '-ldflags=all=-linkmode=external -extldflags=-L/bonus/dir/does/not/exist' +[cgo] go version -m m$GOEXE +[cgo] ! stdout '/extra/dir/does/not/exist' +[cgo] ! stdout '/bonus/dir/does/not/exist' +[cgo] stdout '^\tbuild\tCGO_ENABLED=1$' + -- go.mod -- module example.com/m diff --git a/src/cmd/go/testdata/script/work_goproxy_off.txt b/src/cmd/go/testdata/script/work_goproxy_off.txt new file mode 100644 index 0000000000..767040d09a --- /dev/null +++ b/src/cmd/go/testdata/script/work_goproxy_off.txt @@ -0,0 +1,59 @@ +go work init +go work use . ./sub + +# Verify that the go.mod files for both modules in the workspace are tidy, +# and add missing go.sum entries as needed. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +cd sub +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig +cd .. + +go list -m all +stdout '^rsc\.io/quote v1\.5\.1$' +stdout '^rsc\.io/sampler v1\.3\.1$' + +# Now remove the module dependencies from the module cache. +# Because one module upgrades a transitive dependency needed by another, +# listing the modules in the workspace should error out. + +go clean -modcache +env GOPROXY=off +! go list -m all +stderr '^go: rsc.io/sampler@v1.3.0: module lookup disabled by GOPROXY=off$' + +-- example.go -- +package example + +import _ "rsc.io/sampler" +-- go.mod -- +module example + +go 1.18 + +require rsc.io/sampler v1.3.0 + +require ( + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect + rsc.io/testonly v1.0.0 // indirect +) +-- sub/go.mod -- +module example/sub + +go 1.18 + +require rsc.io/quote v1.5.1 + +require ( + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect + rsc.io/sampler v1.3.1 // indirect +) +-- sub/sub.go -- +package example + +import _ "rsc.io/quote" diff --git a/src/math/big/floatmarsh.go b/src/math/big/floatmarsh.go index d1c1dab069..990e085abe 100644 --- a/src/math/big/floatmarsh.go +++ b/src/math/big/floatmarsh.go @@ -8,6 +8,7 @@ package big import ( "encoding/binary" + "errors" "fmt" ) @@ -67,6 +68,9 @@ func (z *Float) GobDecode(buf []byte) error { *z = Float{} return nil } + if len(buf) < 6 { + return errors.New("Float.GobDecode: buffer too small") + } if buf[0] != floatGobVersion { return fmt.Errorf("Float.GobDecode: encoding version %d not supported", buf[0]) @@ -83,6 +87,9 @@ func (z *Float) GobDecode(buf []byte) error { z.prec = binary.BigEndian.Uint32(buf[2:]) if z.form == finite { + if len(buf) < 10 { + return errors.New("Float.GobDecode: buffer too small for finite form float") + } z.exp = int32(binary.BigEndian.Uint32(buf[6:])) z.mant = z.mant.setBytes(buf[10:]) } diff --git a/src/math/big/floatmarsh_test.go b/src/math/big/floatmarsh_test.go index c056d78b80..401f45a51f 100644 --- a/src/math/big/floatmarsh_test.go +++ b/src/math/big/floatmarsh_test.go @@ -137,3 +137,15 @@ func TestFloatJSONEncoding(t *testing.T) { } } } + +func TestFloatGobDecodeShortBuffer(t *testing.T) { + for _, tc := range [][]byte{ + []byte{0x1, 0x0, 0x0, 0x0}, + []byte{0x1, 0xfa, 0x0, 0x0, 0x0, 0x0}, + } { + err := NewFloat(0).GobDecode(tc) + if err == nil { + t.Error("expected GobDecode to return error for malformed input") + } + } +} diff --git a/src/math/big/ratmarsh.go b/src/math/big/ratmarsh.go index fbc7b6002d..56102e845b 100644 --- a/src/math/big/ratmarsh.go +++ b/src/math/big/ratmarsh.go @@ -45,12 +45,18 @@ func (z *Rat) GobDecode(buf []byte) error { *z = Rat{} return nil } + if len(buf) < 5 { + return errors.New("Rat.GobDecode: buffer too small") + } b := buf[0] if b>>1 != ratGobVersion { return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1) } const j = 1 + 4 i := j + binary.BigEndian.Uint32(buf[j-4:j]) + if len(buf) < int(i) { + return errors.New("Rat.GobDecode: buffer too small") + } z.a.neg = b&1 != 0 z.a.abs = z.a.abs.setBytes(buf[j:i]) z.b.abs = z.b.abs.setBytes(buf[i:]) diff --git a/src/math/big/ratmarsh_test.go b/src/math/big/ratmarsh_test.go index 351d109f8d..55a9878bb8 100644 --- a/src/math/big/ratmarsh_test.go +++ b/src/math/big/ratmarsh_test.go @@ -123,3 +123,15 @@ func TestRatXMLEncoding(t *testing.T) { } } } + +func TestRatGobDecodeShortBuffer(t *testing.T) { + for _, tc := range [][]byte{ + []byte{0x2}, + []byte{0x2, 0x0, 0x0, 0x0, 0xff}, + } { + err := NewRat(1, 2).GobDecode(tc) + if err == nil { + t.Error("expected GobDecode to return error for malformed input") + } + } +} diff --git a/src/runtime/time.go b/src/runtime/time.go index a9ad620776..a47f6b522d 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -391,7 +391,11 @@ func dodeltimer(pp *p, i int) int { if i == 0 { updateTimer0When(pp) } - atomic.Xadd(&pp.numTimers, -1) + n := atomic.Xadd(&pp.numTimers, -1) + if n == 0 { + // If there are no timers, then clearly none are modified. + atomic.Store64(&pp.timerModifiedEarliest, 0) + } return smallestChanged } @@ -415,7 +419,11 @@ func dodeltimer0(pp *p) { siftdownTimer(pp.timers, 0) } updateTimer0When(pp) - atomic.Xadd(&pp.numTimers, -1) + n := atomic.Xadd(&pp.numTimers, -1) + if n == 0 { + // If there are no timers, then clearly none are modified. + atomic.Store64(&pp.timerModifiedEarliest, 0) + } } // modtimer modifies an existing timer. diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 229e3a9105..56128dc882 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -82,6 +82,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in } waspanic := false cgoCtxt := gp.cgoCtxt + stack := gp.stack printing := pcbuf == nil && callback == nil // If the PC is zero, it's likely a nil function call. @@ -114,7 +115,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in if !f.valid() { if callback != nil || printing { print("runtime: unknown pc ", hex(frame.pc), "\n") - tracebackHexdump(gp.stack, &frame, 0) + tracebackHexdump(stack, &frame, 0) } if callback != nil { throw("unknown pc") @@ -174,12 +175,15 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in frame.fn = findfunc(frame.pc) f = frame.fn flag = f.flag + frame.lr = gp.m.curg.sched.lr frame.sp = gp.m.curg.sched.sp + stack = gp.m.curg.stack cgoCtxt = gp.m.curg.cgoCtxt case funcID_systemstack: // systemstack returns normally, so just follow the // stack transition. frame.sp = gp.m.curg.sched.sp + stack = gp.m.curg.stack cgoCtxt = gp.m.curg.cgoCtxt flag &^= funcFlag_SPWRITE } @@ -248,7 +252,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in } if callback != nil || doPrint { print("runtime: unexpected return pc for ", funcname(f), " called from ", hex(frame.lr), "\n") - tracebackHexdump(gp.stack, &frame, lrPtr) + tracebackHexdump(stack, &frame, lrPtr) } if callback != nil { throw("unknown caller pc") @@ -477,6 +481,13 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in break } + if frame.pc == frame.lr && frame.sp == frame.fp { + // If the next frame is identical to the current frame, we cannot make progress. + print("runtime: traceback stuck. pc=", hex(frame.pc), " sp=", hex(frame.sp), "\n") + tracebackHexdump(stack, &frame, frame.sp) + throw("traceback stuck") + } + // Unwind to next frame. frame.fn = flr frame.pc = frame.lr diff --git a/src/testing/testing.go b/src/testing/testing.go index df4dfe4490..05d8f22aff 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -1122,7 +1122,7 @@ func removeAll(path string) error { ) for { err := os.RemoveAll(path) - if !isWindowsAccessDenied(err) { + if !isWindowsRetryable(err) { return err } if start.IsZero() { diff --git a/src/testing/testing_other.go b/src/testing/testing_other.go index 29496d81bc..99a6276a4a 100644 --- a/src/testing/testing_other.go +++ b/src/testing/testing_other.go @@ -6,8 +6,8 @@ package testing -// isWindowsAccessDenied reports whether err is ERROR_ACCESS_DENIED, -// which is defined only on Windows. -func isWindowsAccessDenied(err error) bool { +// isWindowsRetryable reports whether err is a Windows error code +// that may be fixed by retrying a failed filesystem operation. +func isWindowsRetryable(err error) bool { return false } diff --git a/src/testing/testing_windows.go b/src/testing/testing_windows.go index bc76cb80cc..fd48ae9579 100644 --- a/src/testing/testing_windows.go +++ b/src/testing/testing_windows.go @@ -8,11 +8,25 @@ package testing import ( "errors" + "internal/syscall/windows" "syscall" ) -// isWindowsAccessDenied reports whether err is ERROR_ACCESS_DENIED, -// which is defined only on Windows. -func isWindowsAccessDenied(err error) bool { - return errors.Is(err, syscall.ERROR_ACCESS_DENIED) +// isWindowsRetryable reports whether err is a Windows error code +// that may be fixed by retrying a failed filesystem operation. +func isWindowsRetryable(err error) bool { + for { + unwrapped := errors.Unwrap(err) + if unwrapped == nil { + break + } + err = unwrapped + } + if err == syscall.ERROR_ACCESS_DENIED { + return true // Observed in https://go.dev/issue/50051. + } + if err == windows.ERROR_SHARING_VIOLATION { + return true // Observed in https://go.dev/issue/51442. + } + return false } diff --git a/test/fixedbugs/issue52953.go b/test/fixedbugs/issue52953.go new file mode 100644 index 0000000000..2085e4e3fe --- /dev/null +++ b/test/fixedbugs/issue52953.go @@ -0,0 +1,29 @@ +// run + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 52953: miscompilation for composite literal assignment +// when LHS is address-taken. + +package main + +type T struct { + Field1 bool +} + +func main() { + var ret T + ret.Field1 = true + var v *bool = &ret.Field1 + ret = T{Field1: *v} + check(ret.Field1) +} + +//go:noinline +func check(b bool) { + if !b { + panic("FAIL") + } +} diff --git a/test/typeparam/issue51840.go b/test/typeparam/issue51840.go deleted file mode 100644 index f0ca9d1a1d..0000000000 --- a/test/typeparam/issue51840.go +++ /dev/null @@ -1,36 +0,0 @@ -// compile -G=3 - -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -type Addr struct { - hi uint64 - lo uint64 - z *byte -} - -func EqualMap[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool { - for k, v1 := range m1 { - if v2, ok := m2[k]; !ok || v1 != v2 { - return false - } - } - return true -} - -type Set[T comparable] map[T]struct{} - -func NewSet[T comparable](items ...T) Set[T] { - return nil -} - -func (s Set[T]) Equals(other Set[T]) bool { - return EqualMap(s, other) -} - -func main() { - NewSet[Addr](Addr{0, 0, nil}) -} diff --git a/test/typeparam/issue53309.go b/test/typeparam/issue53309.go deleted file mode 100644 index d505f6b58a..0000000000 --- a/test/typeparam/issue53309.go +++ /dev/null @@ -1,42 +0,0 @@ -// run -gcflags=-G=3 - -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -type TaskInput interface { - deps() []*taskDefinition -} - -type Value[T any] interface { - metaValue -} - -type metaValue interface { - TaskInput -} - -type taskDefinition struct { -} - -type taskResult struct { - task *taskDefinition -} - -func (tr *taskResult) deps() []*taskDefinition { - return nil -} - -func use[T any](v Value[T]) { - _, ok := v.(*taskResult) - if !ok { - panic("output must be *taskResult") - } -} - -func main() { - tr := &taskResult{&taskDefinition{}} - use(Value[string](tr)) -} |