Skip to content

Commit 8d2ea29

Browse files
committed
go/types: don't update the underlying type of an imported type
Updating the underlying type of an imported type (even though is was set to the same type again) leads to a race condition if the imported package is imported by separate, concurrently type-checked packages. Fixes #31749. Change-Id: Iabb8e8593eb067eb4816c1df81e545ff52d32c6c Reviewed-on: https://go-review.googlesource.com/c/go/+/201838 Run-TryBot: Robert Griesemer <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 8c6876e commit 8d2ea29

File tree

2 files changed

+44
-7
lines changed

2 files changed

+44
-7
lines changed

src/go/types/decl.go

+14-7
Original file line numberDiff line numberDiff line change
@@ -489,27 +489,34 @@ func (check *Checker) underlying(typ Type) Type {
489489
}
490490

491491
// Otherwise, follow the forward chain.
492-
seen := map[*Named]int{n0: 0, n: 1}
493-
path := []Object{n0.obj, n.obj}
492+
seen := map[*Named]int{n0: 0}
493+
path := []Object{n0.obj}
494494
for {
495495
typ = n.underlying
496-
n, _ = typ.(*Named)
497-
if n == nil {
496+
n1, _ := typ.(*Named)
497+
if n1 == nil {
498498
break // end of chain
499499
}
500500

501+
seen[n] = len(seen)
502+
path = append(path, n.obj)
503+
n = n1
504+
501505
if i, ok := seen[n]; ok {
502506
// cycle
503507
check.cycleError(path[i:])
504508
typ = Typ[Invalid]
505509
break
506510
}
507-
508-
seen[n] = len(seen)
509-
path = append(path, n.obj)
510511
}
511512

512513
for n := range seen {
514+
// We should never have to update the underlying type of an imported type;
515+
// those underlying types should have been resolved during the import.
516+
// Also, doing so would lead to a race condition (was issue #31749).
517+
if n.obj.pkg != check.pkg {
518+
panic("internal error: imported type with unresolved underlying type")
519+
}
513520
n.underlying = typ
514521
}
515522

src/go/types/issues_test.go

+30
Original file line numberDiff line numberDiff line change
@@ -493,3 +493,33 @@ func (h importHelper) Import(path string) (*Package, error) {
493493
}
494494
return h.pkg, nil
495495
}
496+
497+
// TestIssue34921 verifies that we don't update an imported type's underlying
498+
// type when resolving an underlying type. Specifically, when determining the
499+
// underlying type of b.T (which is the underlying type of a.T, which is int)
500+
// we must not set the underlying type of a.T again since that would lead to
501+
// a race condition if package b is imported elsewhere, in a package that is
502+
// concurrently type-checked.
503+
func TestIssue34921(t *testing.T) {
504+
defer func() {
505+
if r := recover(); r != nil {
506+
t.Error(r)
507+
}
508+
}()
509+
510+
var sources = []string{
511+
`package a; type T int`,
512+
`package b; import "a"; type T a.T`,
513+
}
514+
515+
var pkg *Package
516+
for _, src := range sources {
517+
f := mustParse(t, src)
518+
conf := Config{Importer: importHelper{pkg}}
519+
res, err := conf.Check(f.Name.Name, fset, []*ast.File{f}, nil)
520+
if err != nil {
521+
t.Errorf("%q failed to typecheck: %v", src, err)
522+
}
523+
pkg = res // res is imported by the next package in this test
524+
}
525+
}

0 commit comments

Comments
 (0)