aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/types2
diff options
context:
space:
mode:
authorKatie Hockman <katie@golang.org>2021-09-20 15:45:51 -0400
committerKatie Hockman <katie@golang.org>2021-09-20 15:46:10 -0400
commitc6c884be3854f3c94f1ee93a273544c9c5c35df5 (patch)
tree12e3ece09595d359f9edc99025c3f3192aea2213 /src/cmd/compile/internal/types2
parent51ca5706ab2074a624f8a2590a2a81e6a5821e48 (diff)
parentaf72ddfcd7826df9aefb2207b8ac270bb91fea2f (diff)
downloadgo-c6c884be3854f3c94f1ee93a273544c9c5c35df5.tar.gz
go-c6c884be3854f3c94f1ee93a273544c9c5c35df5.zip
[dev.fuzz] all: merge master (af72ddf) into dev.fuzz
This now includes the fix in CL 350729, which means we no longer need to skip the test in dev.fuzz. Conflicts: - src/cmd/compile/internal/noder/unified_test.go Merge List: + 2021-09-20 af72ddfcd7 cmd/compile: extend dump-to-file to handle "genssa" (asm) case. + 2021-09-20 3c764babe7 cmd/go: write go.mod requirements more consistently for go 1.17+ + 2021-09-20 6268468e02 cmd/link: generate DIE for types referenced only through dictionaries + 2021-09-20 6acac8b685 cmd/compile: delay all transforms for generic funcs/methods + 2021-09-20 988f18d61d go/types: export Named._Orig as Named.Origin + 2021-09-20 b6dddaccd7 cmd/compile: fix transform.AssignOp to deal with tricky case + 2021-09-20 9e60c37147 cmd/compile: document register-based ABI for ppc64 + 2021-09-20 79159f2e83 cmd/compile: fix simplification rules on arm/arm64 + 2021-09-20 eff27e858b cmd/compile: ensure constant shift amounts are in range for arm + 2021-09-20 9ebe7c8ec6 go/test: add a test for issue 48344 + 2021-09-20 6f35430faa cmd/compile: allow rotates to be merged with logical ops on arm64 + 2021-09-20 2d9b486420 cmd/compile: update doc at top of iexport.go on the changes for typeparams + 2021-09-20 a81b0dc6ee cmd/compile: rename instType -> instanceType + 2021-09-20 119213566a cmd/cgo: remove hardcoded '-pie' ldflag for linux/arm + 2021-09-20 a83a558733 cmd/compile: fix export/import of range loop. + 2021-09-19 315dbd10c9 cmd/compile: fold double negate on arm64 + 2021-09-19 83b36ffb10 cmd/compile: implement constant rotates on arm64 + 2021-09-19 771b8ea4f4 cmd/compile: fix missing markHiddenClosureDead in deadcode pass + 2021-09-18 c894b442d1 net/rpc: remove warnings on incompatible methods at registration + 2021-09-17 4b654c0eec cmd/compile: SSA ".this" variable + 2021-09-17 f01721efb9 cmd/compile: remove self copies in tail-call wrappers + 2021-09-17 163871feb1 time: re-add space-padded day of year to docs + 2021-09-17 ac7c34767d time: support fractional timezone minutes in MarshalBinary + 2021-09-17 07b30a4f77 cmd/compile: delay transformAssign if lhs/rhs have typeparam + 2021-09-17 c10b980220 cmd/compile: restore tail call for method wrappers + 2021-09-17 50e4508269 cmd/compile: fix import/export of Init and Def fields. + 2021-09-17 3fa35b5f97 go/types: ensure that we always get a new signature in expandNamed + 2021-09-17 3fa7dbeff5 cmd/go: fix GOARCH value in GOAMD64 docs + 2021-09-17 974b0166d6 syscall: implement Pipe using pipe2 syscall on all linux platforms + 2021-09-17 1a49dcb82f syscall: remove //sysnb comment generating Setreuid for linux/arm64 + 2021-09-17 cea7a71d40 cmd/compile: fix generic type handling in crawler + 2021-09-17 74e384f50d internal/poll: inject a hook into the runtime finalizer to count the closed pipes + 2021-09-17 323c6f74d3 log: don't format if writing to io.Discard + 2021-09-17 7f36ef0aff cmd/compile/internal/noder: hide TestUnifiedCompare behind -cmp flag + 2021-09-17 70493b3eb0 runtime/cgo: save and restore X3 (aka GP) for crosscall1 on riscv64 + 2021-09-17 6d02ce8584 runtime: fix prettyprinting of parametric types in gdb + 2021-09-17 6602c86a38 cmd/internal/obj/riscv: improve instruction validation + 2021-09-17 14e812bfc5 syscall: do not use handle lists on windows when NoInheritHandles is true + 2021-09-16 8d2a9c32a2 all: remove incorrectly repeated words in comments + 2021-09-16 af9da137a9 A+C: update name to real name and add to AUTHORS + 2021-09-16 265b59aefd cmd/cgo: for godefs, don't let field prefix removal cause duplicates + 2021-09-16 4efdaa7bc7 testing: skip panics when picking the line number for decoration + 2021-09-16 e09dcc211a go/types, types2: add an additional shift test case + 2021-09-16 5402b4376c spec: fix incorrect type in a shift example + 2021-09-16 d09e09bc61 cmd/compile: fixing writebarrier.go for -G=3 + 2021-09-16 bcdc61d830 cmd/compile: preserve statements better in expandCalls + 2021-09-16 48e2b1ea91 cmd/compile: fix LocResults formatting + 2021-09-16 b1bedc0774 cmd/go: add GOAMD64 environment variable + 2021-09-16 04f5116c98 cmd/go: clean paths before checking same directory + 2021-09-16 e7dbe3908e cmd/cgo: add missing tab in exports for a result of void + 2021-09-15 cfa233d76b cmd/compile: remove unneeded early transforms, with dictionary change + 2021-09-15 59a9a035ff cmd/compile: switch to computing dict format on instantiated functions + 2021-09-15 0edc6c4fa0 cmd/internal/obj/ppc64: generate prologue code compatible with new ABI + 2021-09-15 03df68d3c3 runtime: fix setting of cpu features for amd64 + 2021-09-15 6196979365 cmd/go/internal/modload: prevent tidy downgrading disambiguating modules + 2021-09-15 72bb8185b5 cmd/compile: emit DWARF info about dictionary entries + 2021-09-15 5b48fca1fa cmd/compile: mark wrapper functions with DW_AT_trampoline + 2021-09-15 e4dfd788e6 go/internal/gcimporter,cmd/compile: minor clean-up in iimport.go + 2021-09-15 4847c47cb8 cmd/compile/internal/types2: eliminate Named.instPos + 2021-09-15 3100f54f20 cmd/compile/internal/types2: merge Named type loading and expansion + 2021-09-15 738cebb174 cmd/compile/internal/types2: implement Identical for *Union types + 2021-09-15 b26d325cb1 cmd/compile/internal/types2: remove some unnecessary loading/expansion of Named types + 2021-09-15 9fc28892cb cmd/compile/internal/types2: export TypeHash, return value without blanks + 2021-09-15 2da3375e9b runtime: in adjustTimers back up as far as necessary + 2021-09-15 c7f2f51fed cmd/go: remove subcommand prefix from error messages + 2021-09-15 0bb40b08c4 go/types: implement Identical for *Union types + 2021-09-15 cb4e1de021 go/types: minor cleanup of instantiation + 2021-09-15 a0f3129466 go/types: instantiate methods when instantiating Named types + 2021-09-14 bf26e43d0f go/types: eliminate Named.instPos + 2021-09-14 2933c451a0 go/types: merge Named type loading and expansion + 2021-09-14 137543bb93 cmd/compile: set IsShape based on type being in the Shapes pkg + 2021-09-14 3a72175cdc cmd/compile: fix test/typeparam/mdempsky/4.go for -G=3 + 2021-09-14 b2c04f0d48 runtime: avoid loop variable capture in test + 2021-09-14 181e8cde30 go/internal/gcimporter: remove outdated comment + 2021-09-14 8699425b55 syscall: remove use of IN_KUBERNETES in test + 2021-09-14 b3c6de9dcd cmd/internal/obj/ppc64: allow VR register arguments to VS registers + 2021-09-14 ee91bb8319 cmd/compile: prevent typecheck importer reading type parameter twice + 2021-09-14 2953cd0083 go/internal/gcimporter: prevent importReader reading type parameter twice + 2021-09-14 b8c802b116 cmd/compile: prevent importReader reading type parameter twice + 2021-09-14 4a4221e818 all: remove some unused code + 2021-09-14 71adc658de runtime: change time.now to ABIInternal + 2021-09-14 146e8d4994 reflect: use Value.Len instead of conversion to slice header + 2021-09-13 9a58aa267e spec: fix prose about terminating statements + 2021-09-13 42057e9848 cmd/compile: save the note of fields when translating struct + 2021-09-13 960d036f8f cmd/go: add missing parenthesis in a call to "PrintVersion" + 2021-09-13 81a4fe6fd2 cmd/link/internal/ld: re-enable DWARF tests on solaris/illumos + 2021-09-13 f93a63addb reflect: add a floating point section to DeepEqual tests + 2021-09-13 a0c409cbc8 reflect: add fast paths for common, simple Kinds to DeepEqual + 2021-09-13 ac40c9872f reflect: fix _faststr optimization + 2021-09-13 c8a58f29dc cmd/go: add test to check for a potential workspace loading issue + 2021-09-13 e74e363a6b strings: add Clone function + 2021-09-13 bced369a50 cmd/link: minor code cleanup in dwarf gen + 2021-09-13 c3b217a0e5 cmd/go: document 'go install cmd@version' ignores vendor directories + 2021-09-12 ad97d204f0 go/types: remove some unnecessary loading/expansion of Named types + 2021-09-12 0d8a4bfc96 bufio: add Writer.AvailableBuffer + 2021-09-11 23832ba2e2 reflect: optimize for maps with string keys + 2021-09-11 a50225a0dc bufio: make Reader.Reset and Writer.Reset work on the zero value + 2021-09-10 cf2fe5d6f1 doc/asm: fix HTML markup + 2021-09-10 1bf2cd1291 debug/elf: retain original error message when getSymbols fails. + 2021-09-10 5a4b9f9494 time: reference -tags=timetzdata in testing panic + 2021-09-10 025308fe08 testing: increase alternation precedence + 2021-09-10 5a94a90d84 cmd/compile/internal/types2: better error message for invalid array decls + 2021-09-10 da1aa65053 cmd/compile/internal/syntax: correct follow token for type parameter lists + 2021-09-10 96ab854ab0 cmd/compile/internal: better AST line highlight in ssa.html + 2021-09-10 90c5660616 embed: guarantee the returned file of FS.Open implements io.Seeker + 2021-09-10 c69f5c0d76 cmd/compile: add support for Abs and Copysign intrinsics on riscv64 + 2021-09-10 2091bd3f26 cmd/compile: simiplify arm64 bitfield optimizations + 2021-09-09 b32209d22d cmd/compile: fix test case for unified IR (fix build) + 2021-09-09 1a708bcf1d cmd/compile: don't crash while reporting invalid alias cycle + 2021-09-09 426ff3746f cmd/cgo, runtime/cgo: avoid GCC/clang conversion warnings + 2021-09-09 73483df406 cmd/compile/internal/syntax: better error message for missing type constraint + 2021-09-09 e1c3f2158f time: propagate "," separator for fractional seconds into Format + 2021-09-09 c981874a5a cmd/compile: fix implement for closure in a global assignment + 2021-09-09 2c4f389c02 cmd/link: enable internal linker in more cases for ppc64le + 2021-09-09 fb84e99eb7 test: add compiler regress tests for #46461 + 2021-09-09 b9e1a24581 cmd/compile: fix case where init info of OAS node is dropped + 2021-09-09 f9271e4f85 go/types, types2: rename RParams -> RecvTypeParams + 2021-09-09 ea434450c2 reflect: add hooks for dealing with narrow width floats + 2021-09-09 a53e3d5f88 net: deprecate (net.Error).Temporary + 2021-09-09 19457a58e5 cmd/compile: stenciled conversions might be NOPs + 2021-09-09 a295b3cec8 test: re-enable AsmCheck tests for types2-based frontends + 2021-09-09 66f0d35f71 go/types: reduce number of delayed functions + 2021-09-09 d2a77f1c76 go/types: handle recursive type parameter constraints + 2021-09-09 9e1eea6f8b go/types: detect constraint type inference cycles + 2021-09-09 b86e8dd0f3 test/typeparam: fix issue48094b test build + 2021-09-09 c84f3a4004 syscall: drop fallback to pipe in Pipe on linux/arm + 2021-09-09 376a079762 cmd/compile: fix unified IR panic when expanding nested inline function + 2021-09-09 6edc57983a internal/poll: report open fds when TestSplicePipePool fails + 2021-09-09 2481f6e367 cmd/compile: fix wrong instantiated type for embedded receiver + 2021-09-09 d62866ef79 cmd/compile: move checkptr alignment to SSA generation + 2021-09-09 8fad81cd62 cmd/compile: fold handling OCONV logic to separate function + 2021-09-09 9cbc76bdf9 cmd/internal/obj/arm64: add checks for incorrect use of REGTMP register + 2021-09-09 42563f89d7 cmd/compile: remove 'ext' fields from unified IR reader/writer types + 2021-09-09 4c52eac49b cmd/compile: simplify value coding for unified IR + 2021-09-09 e30a09013b cmd/compile: extrapolate $GOROOT in unified IR + 2021-09-08 a1f6208e56 go/types, types2: add Environment to Config + 2021-09-08 f5f8a911d8 cmd/compile/internal/types2: spell out 'Type' in type parameter APIs + 2021-09-08 bff39cf6cb cmd/compile: add automated rewrite cycle detection + 2021-09-08 b61e1ed863 cmd/compile/internal/types2: temporarily pin the Checker to Interface during checking + 2021-09-08 47f3e1e02c cmd/compile/internal/types2: move NewTypeParam off of Checker + 2021-09-08 ccc927b8f6 cmd/compile/internal/types2: move typeHash to environment.go + 2021-09-08 30e9bfbcef cmd/compile/internal/types2: implement deduplication of instances using the Environment + 2021-09-08 0406d3a8e5 go/ast: rename MultiIndexExpr to IndexListExpr Change-Id: I7f917d45b0507c122c212305144b0b455618ff54
Diffstat (limited to 'src/cmd/compile/internal/types2')
-rw-r--r--src/cmd/compile/internal/types2/api.go5
-rw-r--r--src/cmd/compile/internal/types2/api_test.go45
-rw-r--r--src/cmd/compile/internal/types2/assignments.go2
-rw-r--r--src/cmd/compile/internal/types2/builtins.go2
-rw-r--r--src/cmd/compile/internal/types2/call.go24
-rw-r--r--src/cmd/compile/internal/types2/check.go7
-rw-r--r--src/cmd/compile/internal/types2/decl.go10
-rw-r--r--src/cmd/compile/internal/types2/environment.go81
-rw-r--r--src/cmd/compile/internal/types2/errors.go2
-rw-r--r--src/cmd/compile/internal/types2/errors_test.go1
-rw-r--r--src/cmd/compile/internal/types2/index.go2
-rw-r--r--src/cmd/compile/internal/types2/infer.go2
-rw-r--r--src/cmd/compile/internal/types2/instantiate.go62
-rw-r--r--src/cmd/compile/internal/types2/instantiate_test.go62
-rw-r--r--src/cmd/compile/internal/types2/interface.go15
-rw-r--r--src/cmd/compile/internal/types2/lookup.go24
-rw-r--r--src/cmd/compile/internal/types2/named.go140
-rw-r--r--src/cmd/compile/internal/types2/object.go20
-rw-r--r--src/cmd/compile/internal/types2/predicates.go18
-rw-r--r--src/cmd/compile/internal/types2/signature.go44
-rw-r--r--src/cmd/compile/internal/types2/sizeof_test.go4
-rw-r--r--src/cmd/compile/internal/types2/subst.go105
-rw-r--r--src/cmd/compile/internal/types2/testdata/fixedbugs/issue43527.go216
-rw-r--r--src/cmd/compile/internal/types2/testdata/fixedbugs/issue47887.go228
-rw-r--r--src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go22
-rw-r--r--src/cmd/compile/internal/types2/testdata/fixedbugs/issue48234.go210
-rw-r--r--src/cmd/compile/internal/types2/type.go2
-rw-r--r--src/cmd/compile/internal/types2/typelists.go16
-rw-r--r--src/cmd/compile/internal/types2/typeparam.go12
-rw-r--r--src/cmd/compile/internal/types2/typestring.go115
-rw-r--r--src/cmd/compile/internal/types2/typexpr.go10
-rw-r--r--src/cmd/compile/internal/types2/unify.go3
-rw-r--r--src/cmd/compile/internal/types2/universe.go4
33 files changed, 555 insertions, 340 deletions
diff --git a/src/cmd/compile/internal/types2/api.go b/src/cmd/compile/internal/types2/api.go
index b2938b84da1..6914e6c89f7 100644
--- a/src/cmd/compile/internal/types2/api.go
+++ b/src/cmd/compile/internal/types2/api.go
@@ -108,6 +108,11 @@ type ImporterFrom interface {
// A Config specifies the configuration for type checking.
// The zero value for Config is a ready-to-use default configuration.
type Config struct {
+ // Environment is the environment used for resolving global
+ // identifiers. If nil, the type checker will initialize this
+ // field with a newly created environment.
+ Environment *Environment
+
// GoVersion describes the accepted Go language version. The string
// must follow the format "go%d.%d" (e.g. "go1.12") or ist must be
// empty; an empty string indicates the latest language version.
diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go
index 039a6c0e5e7..cd5a61332a7 100644
--- a/src/cmd/compile/internal/types2/api_test.go
+++ b/src/cmd/compile/internal/types2/api_test.go
@@ -145,6 +145,7 @@ func TestValuesInfo(t *testing.T) {
{`package f7b; var _ = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`},
{`package g0; const (a = len([iota]int{}); b; c); const _ = c`, `c`, `int`, `2`}, // issue #22341
+ {`package g1; var(j int32; s int; n = 1.0<<s == j)`, `1.0`, `int32`, `1`}, // issue #48422
}
for _, test := range tests {
@@ -1645,6 +1646,48 @@ func TestIdentical_issue15173(t *testing.T) {
}
}
+func TestIdenticalUnions(t *testing.T) {
+ tname := NewTypeName(nopos, nil, "myInt", nil)
+ myInt := NewNamed(tname, Typ[Int], nil)
+ tmap := map[string]*Term{
+ "int": NewTerm(false, Typ[Int]),
+ "~int": NewTerm(true, Typ[Int]),
+ "string": NewTerm(false, Typ[String]),
+ "~string": NewTerm(true, Typ[String]),
+ "myInt": NewTerm(false, myInt),
+ }
+ makeUnion := func(s string) *Union {
+ parts := strings.Split(s, "|")
+ var terms []*Term
+ for _, p := range parts {
+ term := tmap[p]
+ if term == nil {
+ t.Fatalf("missing term %q", p)
+ }
+ terms = append(terms, term)
+ }
+ return NewUnion(terms)
+ }
+ for _, test := range []struct {
+ x, y string
+ want bool
+ }{
+ // These tests are just sanity checks. The tests for type sets and
+ // interfaces provide much more test coverage.
+ {"int|~int", "~int", true},
+ {"myInt|~int", "~int", true},
+ {"int|string", "string|int", true},
+ {"int|int|string", "string|int", true},
+ {"myInt|string", "int|string", false},
+ } {
+ x := makeUnion(test.x)
+ y := makeUnion(test.y)
+ if got := Identical(x, y); got != test.want {
+ t.Errorf("Identical(%v, %v) = %t", test.x, test.y, got)
+ }
+ }
+}
+
func TestIssue15305(t *testing.T) {
const src = "package p; func f() int16; var _ = f(undef)"
f, err := parseSrc("issue15305.go", src)
@@ -1871,7 +1914,7 @@ func TestInstantiate(t *testing.T) {
// type T should have one type parameter
T := pkg.Scope().Lookup("T").Type().(*Named)
- if n := T.TParams().Len(); n != 1 {
+ if n := T.TypeParams().Len(); n != 1 {
t.Fatalf("expected 1 type parameter; found %d", n)
}
diff --git a/src/cmd/compile/internal/types2/assignments.go b/src/cmd/compile/internal/types2/assignments.go
index 6184fc2ea50..29d63cf819a 100644
--- a/src/cmd/compile/internal/types2/assignments.go
+++ b/src/cmd/compile/internal/types2/assignments.go
@@ -68,7 +68,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
// x.typ is typed
// A generic (non-instantiated) function value cannot be assigned to a variable.
- if sig := asSignature(x.typ); sig != nil && sig.TParams().Len() > 0 {
+ if sig := asSignature(x.typ); sig != nil && sig.TypeParams().Len() > 0 {
check.errorf(x, "cannot use generic function %s without instantiation in %s", x, context)
}
diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go
index e3844d5163e..3b8d85859a7 100644
--- a/src/cmd/compile/internal/types2/builtins.go
+++ b/src/cmd/compile/internal/types2/builtins.go
@@ -826,7 +826,7 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
// type param is placed in the current package so export/import
// works as expected.
tpar := NewTypeName(nopos, check.pkg, "<type parameter>", nil)
- ptyp := check.NewTypeParam(tpar, NewInterfaceType(nil, []Type{NewUnion(terms)})) // assigns type to tpar as a side-effect
+ ptyp := check.newTypeParam(tpar, NewInterfaceType(nil, []Type{NewUnion(terms)})) // assigns type to tpar as a side-effect
ptyp.index = tp.index
return ptyp
diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go
index 5bf17876c15..ba3bb475a31 100644
--- a/src/cmd/compile/internal/types2/call.go
+++ b/src/cmd/compile/internal/types2/call.go
@@ -30,7 +30,7 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
// check number of type arguments (got) vs number of type parameters (want)
sig := x.typ.(*Signature)
- got, want := len(targs), sig.TParams().Len()
+ got, want := len(targs), sig.TypeParams().Len()
if !useConstraintTypeInference && got != want || got > want {
check.errorf(xlist[got-1], "got %d type arguments but want %d", got, want)
x.mode = invalid
@@ -41,7 +41,7 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
// if we don't have enough type arguments, try type inference
inferred := false
if got < want {
- targs = check.infer(inst.Pos(), sig.TParams().list(), targs, nil, nil, true)
+ targs = check.infer(inst.Pos(), sig.TypeParams().list(), targs, nil, nil, true)
if targs == nil {
// error was already reported
x.mode = invalid
@@ -61,7 +61,7 @@ func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
// instantiate function signature
res := check.instantiate(x.Pos(), sig, targs, poslist).(*Signature)
- assert(res.TParams().Len() == 0) // signature is not generic anymore
+ assert(res.TypeParams().Len() == 0) // signature is not generic anymore
if inferred {
check.recordInferred(inst, targs, res)
}
@@ -166,7 +166,7 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
assert(len(targs) == len(xlist))
// check number of type arguments (got) vs number of type parameters (want)
- got, want := len(targs), sig.TParams().Len()
+ got, want := len(targs), sig.TypeParams().Len()
if got > want {
check.errorf(xlist[want], "got %d type arguments but want %d", got, want)
check.use(call.ArgList...)
@@ -200,7 +200,7 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
// if type inference failed, a parametrized result must be invalidated
// (operands cannot have a parametrized type)
- if x.mode == value && sig.TParams().Len() > 0 && isParameterized(sig.TParams().list(), x.typ) {
+ if x.mode == value && sig.TypeParams().Len() > 0 && isParameterized(sig.TypeParams().list(), x.typ) {
x.mode = invalid
}
@@ -328,7 +328,7 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T
}
// infer type arguments and instantiate signature if necessary
- if sig.TParams().Len() > 0 {
+ if sig.TypeParams().Len() > 0 {
if !check.allowVersion(check.pkg, 1, 18) {
if iexpr, _ := call.Fun.(*syntax.IndexExpr); iexpr != nil {
check.softErrorf(iexpr.Pos(), "function instantiation requires go1.18 or later")
@@ -338,21 +338,21 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T
}
// TODO(gri) provide position information for targs so we can feed
// it to the instantiate call for better error reporting
- targs := check.infer(call.Pos(), sig.TParams().list(), targs, sigParams, args, true)
+ targs := check.infer(call.Pos(), sig.TypeParams().list(), targs, sigParams, args, true)
if targs == nil {
return // error already reported
}
// compute result signature
rsig = check.instantiate(call.Pos(), sig, targs, nil).(*Signature)
- assert(rsig.TParams().Len() == 0) // signature is not generic anymore
+ assert(rsig.TypeParams().Len() == 0) // signature is not generic anymore
check.recordInferred(call, targs, rsig)
// Optimization: Only if the parameter list was adjusted do we
// need to compute it from the adjusted list; otherwise we can
// simply use the result signature's parameter list.
if adjusted {
- sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.TParams().list(), targs), nil).(*Tuple)
+ sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.TypeParams().list(), targs), nil).(*Tuple)
} else {
sigParams = rsig.params
}
@@ -535,7 +535,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
// the signature accordingly.
// TODO(gri) factor this code out
sig := m.typ.(*Signature)
- if sig.RParams().Len() > 0 {
+ if sig.RecvTypeParams().Len() > 0 {
// For inference to work, we must use the receiver type
// matching the receiver in the actual method declaration.
// If the method is embedded, the matching receiver is the
@@ -564,7 +564,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
// the receiver type arguments here, the receiver must be be otherwise invalid
// and an error has been reported elsewhere.
arg := operand{mode: variable, expr: x.expr, typ: recv}
- targs := check.infer(m.pos, sig.RParams().list(), nil, NewTuple(sig.recv), []*operand{&arg}, false /* no error reporting */)
+ targs := check.infer(m.pos, sig.RecvTypeParams().list(), nil, NewTuple(sig.recv), []*operand{&arg}, false /* no error reporting */)
//check.dump("### inferred targs = %s", targs)
if targs == nil {
// We may reach here if there were other errors (see issue #40056).
@@ -574,7 +574,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
// (If we modify m, some tests will fail; possibly because the m is in use.)
// TODO(gri) investigate and provide a correct explanation here
copy := *m
- copy.typ = check.subst(e.Pos(), m.typ, makeSubstMap(sig.RParams().list(), targs), nil)
+ copy.typ = check.subst(e.Pos(), m.typ, makeSubstMap(sig.RecvTypeParams().list(), targs), nil)
obj = &copy
}
// TODO(gri) we also need to do substitution for parameterized interface methods
diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go
index 4226b4de820..24a05e6b370 100644
--- a/src/cmd/compile/internal/types2/check.go
+++ b/src/cmd/compile/internal/types2/check.go
@@ -86,7 +86,6 @@ type Checker struct {
nextID uint64 // unique Id for type parameters (first valid Id is 1)
objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info
impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package
- typMap map[string]*Named // maps an instantiated named type hash to a *Named type
// pkgPathMap maps package names to the set of distinct import paths we've
// seen for that name, anywhere in the import graph. It is used for
@@ -171,6 +170,11 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
conf = new(Config)
}
+ // make sure we have an environment
+ if conf.Environment == nil {
+ conf.Environment = NewEnvironment()
+ }
+
// make sure we have an info struct
if info == nil {
info = new(Info)
@@ -188,7 +192,6 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
version: version,
objMap: make(map[Object]*declInfo),
impMap: make(map[importKey]*Package),
- typMap: make(map[string]*Named),
}
}
diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go
index cd97080824a..26e050511e2 100644
--- a/src/cmd/compile/internal/types2/decl.go
+++ b/src/cmd/compile/internal/types2/decl.go
@@ -317,7 +317,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
}
case *Named:
- t.expand(check.typMap)
+ t.resolve(check.conf.Environment)
// don't touch the type if it is from a different package or the Universe scope
// (doing so would lead to a race condition - was issue #35049)
@@ -592,13 +592,13 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
named.underlying = under(named)
// If the RHS is a type parameter, it must be from this type declaration.
- if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.TParams().list(), tpar) < 0 {
+ if tpar, _ := named.underlying.(*TypeParam); tpar != nil && tparamIndex(named.TypeParams().list(), tpar) < 0 {
check.errorf(tdecl.Type, "cannot use function type parameter %s as RHS in type declaration", tpar)
named.underlying = Typ[Invalid]
}
}
-func (check *Checker) collectTypeParams(dst **TParamList, list []*syntax.Field) {
+func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Field) {
tparams := make([]*TypeParam, len(list))
// Declare type parameters up-front.
@@ -648,7 +648,7 @@ func (check *Checker) declareTypeParam(name *syntax.Name) *TypeParam {
// constraints to make sure we don't rely on them if they
// are not properly set yet.
tname := NewTypeName(name.Pos(), check.pkg, name.Value, nil)
- tpar := check.NewTypeParam(tname, Typ[Invalid]) // assigns type to tname as a side-effect
+ tpar := check.newTypeParam(tname, Typ[Invalid]) // assigns type to tname as a side-effect
check.declare(check.scope, name, tname, check.scope.pos) // TODO(gri) check scope position
return tpar
}
@@ -715,7 +715,7 @@ func (check *Checker) collectMethods(obj *TypeName) {
}
if base != nil {
- base.load() // TODO(mdempsky): Probably unnecessary.
+ base.resolve(nil) // TODO(mdempsky): Probably unnecessary.
base.methods = append(base.methods, m)
}
}
diff --git a/src/cmd/compile/internal/types2/environment.go b/src/cmd/compile/internal/types2/environment.go
new file mode 100644
index 00000000000..fe9a3099fee
--- /dev/null
+++ b/src/cmd/compile/internal/types2/environment.go
@@ -0,0 +1,81 @@
+// Copyright 2021 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 types2
+
+import (
+ "bytes"
+ "strings"
+ "sync"
+)
+
+// An Environment is an opaque type checking environment. It may be used to
+// share identical type instances across type-checked packages or calls to
+// Instantiate.
+//
+// It is safe for concurrent use.
+type Environment struct {
+ mu sync.Mutex
+ typeMap map[string]*Named // type hash -> instance
+ nextID int // next unique ID
+ seen map[*Named]int // assigned unique IDs
+}
+
+// NewEnvironment creates a new Environment.
+func NewEnvironment() *Environment {
+ return &Environment{
+ typeMap: make(map[string]*Named),
+ seen: make(map[*Named]int),
+ }
+}
+
+// TypeHash returns a string representation of typ, which can be used as an exact
+// type hash: types that are identical produce identical string representations.
+// If typ is a *Named type and targs is not empty, typ is printed as if it were
+// instantiated with targs. The result is guaranteed to not contain blanks (" ").
+func (env *Environment) TypeHash(typ Type, targs []Type) string {
+ assert(env != nil)
+ assert(typ != nil)
+ var buf bytes.Buffer
+
+ h := newTypeHasher(&buf, env)
+ if named, _ := typ.(*Named); named != nil && len(targs) > 0 {
+ // Don't use WriteType because we need to use the provided targs
+ // and not any targs that might already be with the *Named type.
+ h.typePrefix(named)
+ h.typeName(named.obj)
+ h.typeList(targs)
+ } else {
+ assert(targs == nil)
+ h.typ(typ)
+ }
+
+ return strings.Replace(buf.String(), " ", "#", -1) // ReplaceAll is not available in Go1.4
+}
+
+// typeForHash returns the recorded type for the type hash h, if it exists.
+// If no type exists for h and n is non-nil, n is recorded for h.
+func (env *Environment) typeForHash(h string, n *Named) *Named {
+ env.mu.Lock()
+ defer env.mu.Unlock()
+ if existing := env.typeMap[h]; existing != nil {
+ return existing
+ }
+ if n != nil {
+ env.typeMap[h] = n
+ }
+ return n
+}
+
+// idForType returns a unique ID for the pointer n.
+func (env *Environment) idForType(n *Named) int {
+ env.mu.Lock()
+ defer env.mu.Unlock()
+ id, ok := env.seen[n]
+ if !ok {
+ id = env.nextID
+ env.seen[n] = id
+ env.nextID++
+ }
+ return id
+}
diff --git a/src/cmd/compile/internal/types2/errors.go b/src/cmd/compile/internal/types2/errors.go
index a68273271b7..ea43fab1782 100644
--- a/src/cmd/compile/internal/types2/errors.go
+++ b/src/cmd/compile/internal/types2/errors.go
@@ -246,7 +246,7 @@ func stripAnnotations(s string) string {
var b bytes.Buffer
for _, r := range s {
// strip #'s and subscript digits
- if r != instanceMarker && !('₀' <= r && r < '₀'+10) { // '₀' == U+2080
+ if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
b.WriteRune(r)
}
}
diff --git a/src/cmd/compile/internal/types2/errors_test.go b/src/cmd/compile/internal/types2/errors_test.go
index e1f0e83fc97..72a2ce3655a 100644
--- a/src/cmd/compile/internal/types2/errors_test.go
+++ b/src/cmd/compile/internal/types2/errors_test.go
@@ -35,7 +35,6 @@ func TestStripAnnotations(t *testing.T) {
{"foo", "foo"},
{"foo₀", "foo"},
{"foo(T₀)", "foo(T)"},
- {"#foo(T₀)", "foo(T)"},
} {
got := stripAnnotations(test.in)
if got != test.want {
diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go
index febfd21ea33..848a70dea8f 100644
--- a/src/cmd/compile/internal/types2/index.go
+++ b/src/cmd/compile/internal/types2/index.go
@@ -34,7 +34,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
return false
case value:
- if sig := asSignature(x.typ); sig != nil && sig.TParams().Len() > 0 {
+ if sig := asSignature(x.typ); sig != nil && sig.TypeParams().Len() > 0 {
// function instantiation
return true
}
diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go
index bb7270b346a..c2a8155dc7b 100644
--- a/src/cmd/compile/internal/types2/infer.go
+++ b/src/cmd/compile/internal/types2/infer.go
@@ -562,7 +562,7 @@ func (w *cycleFinder) typ(typ Type) {
w.typ(t.elem)
case *Named:
- for _, tpar := range t.TArgs().list() {
+ for _, tpar := range t.TypeArgs().list() {
w.typ(tpar)
}
diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go
index c882699d1d5..7a9279943c1 100644
--- a/src/cmd/compile/internal/types2/instantiate.go
+++ b/src/cmd/compile/internal/types2/instantiate.go
@@ -13,21 +13,6 @@ import (
"fmt"
)
-// An Environment is an opaque type checking environment. It may be used to
-// share identical type instances across type checked packages or calls to
-// Instantiate.
-type Environment struct {
- // For now, Environment just hides a Checker.
- // Eventually, we strive to remove the need for a checker.
- check *Checker
-}
-
-// NewEnvironment returns a new Environment, initialized with the given
-// Checker, or nil.
-func NewEnvironment(check *Checker) *Environment {
- return &Environment{check}
-}
-
// Instantiate instantiates the type typ with the given type arguments targs.
// typ must be a *Named or a *Signature type, and its number of type parameters
// must match the number of provided type arguments. The result is a new,
@@ -46,22 +31,18 @@ func NewEnvironment(check *Checker) *Environment {
// TODO(rfindley): change this function to also return an error if lengths of
// tparams and targs do not match.
func Instantiate(env *Environment, typ Type, targs []Type, validate bool) (Type, error) {
- var check *Checker
- if env != nil {
- check = env.check
- }
- inst := check.instance(nopos, typ, targs)
+ inst := (*Checker)(nil).instance(nopos, typ, targs, env)
var err error
if validate {
var tparams []*TypeParam
switch t := typ.(type) {
case *Named:
- tparams = t.TParams().list()
+ tparams = t.TypeParams().list()
case *Signature:
- tparams = t.TParams().list()
+ tparams = t.TypeParams().list()
}
- if i, err := check.verify(nopos, tparams, targs); err != nil {
+ if i, err := (*Checker)(nil).verify(nopos, tparams, targs); err != nil {
return inst, ArgumentError{i, err}
}
}
@@ -90,7 +71,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, posLis
}()
}
- inst := check.instance(pos, typ, targs)
+ inst := check.instance(pos, typ, targs, check.conf.Environment)
assert(len(posList) <= len(targs))
check.later(func() {
@@ -99,9 +80,9 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, posLis
var tparams []*TypeParam
switch t := typ.(type) {
case *Named:
- tparams = t.TParams().list()
+ tparams = t.TypeParams().list()
case *Signature:
- tparams = t.TParams().list()
+ tparams = t.TypeParams().list()
}
// Avoid duplicate errors; instantiate will have complained if tparams
// and targs do not have the same length.
@@ -122,35 +103,40 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, posLis
// instance creates a type or function instance using the given original type
// typ and arguments targs. For Named types the resulting instance will be
// unexpanded.
-func (check *Checker) instance(pos syntax.Pos, typ Type, targs []Type) Type {
+func (check *Checker) instance(pos syntax.Pos, typ Type, targs []Type, env *Environment) Type {
switch t := typ.(type) {
case *Named:
- h := typeHash(t, targs)
- if check != nil {
- // typ may already have been instantiated with identical type arguments.
- // In that case, re-use the existing instance.
- if named := check.typMap[h]; named != nil {
+ var h string
+ if env != nil {
+ h = env.TypeHash(t, targs)
+ // typ may already have been instantiated with identical type arguments. In
+ // that case, re-use the existing instance.
+ if named := env.typeForHash(h, nil); named != nil {
return named
}
}
tname := NewTypeName(pos, t.obj.pkg, t.obj.name, nil)
- named := check.newNamed(tname, t, nil, nil, nil) // methods and tparams are set when named is loaded
+ named := check.newNamed(tname, t, nil, nil, nil) // methods and tparams are set when named is resolved
named.targs = NewTypeList(targs)
- named.instPos = &pos
- if check != nil {
- check.typMap[h] = named
+ named.resolver = func(env *Environment, n *Named) (*TypeParamList, Type, []*Func) {
+ return expandNamed(env, n, pos)
+ }
+ if env != nil {
+ // It's possible that we've lost a race to add named to the environment.
+ // In this case, use whichever instance is recorded in the environment.
+ named = env.typeForHash(h, named)
}
return named
case *Signature:
- tparams := t.TParams()
+ tparams := t.TypeParams()
if !check.validateTArgLen(pos, tparams.Len(), len(targs)) {
return Typ[Invalid]
}
if tparams.Len() == 0 {
return typ // nothing to do (minor optimization)
}
- sig := check.subst(pos, typ, makeSubstMap(tparams.list(), targs), nil).(*Signature)
+ sig := check.subst(pos, typ, makeSubstMap(tparams.list(), targs), env).(*Signature)
// If the signature doesn't use its type parameters, subst
// will not make a copy. In that case, make a copy now (so
// we can set tparams to nil w/o causing side-effects).
diff --git a/src/cmd/compile/internal/types2/instantiate_test.go b/src/cmd/compile/internal/types2/instantiate_test.go
new file mode 100644
index 00000000000..69a26491cb5
--- /dev/null
+++ b/src/cmd/compile/internal/types2/instantiate_test.go
@@ -0,0 +1,62 @@
+// Copyright 2021 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 types2_test
+
+import (
+ . "cmd/compile/internal/types2"
+ "testing"
+)
+
+func TestInstantiateEquality(t *testing.T) {
+ const src = genericPkg + "p; type T[P any] int"
+ pkg, err := pkgFor(".", src, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ T := pkg.Scope().Lookup("T").Type().(*Named)
+ // Instantiating the same type twice should result in pointer-equivalent
+ // instances.
+ env := NewEnvironment()
+ res1, err := Instantiate(env, T, []Type{Typ[Int]}, false)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res2, err := Instantiate(env, T, []Type{Typ[Int]}, false)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if res1 != res2 {
+ t.Errorf("first instance (%s) not pointer-equivalent to second instance (%s)", res1, res2)
+ }
+}
+func TestInstantiateNonEquality(t *testing.T) {
+ const src = genericPkg + "p; type T[P any] int"
+ pkg1, err := pkgFor(".", src, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ pkg2, err := pkgFor(".", src, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // We consider T1 and T2 to be distinct types, so their instances should not
+ // be deduplicated by the environment.
+ T1 := pkg1.Scope().Lookup("T").Type().(*Named)
+ T2 := pkg2.Scope().Lookup("T").Type().(*Named)
+ env := NewEnvironment()
+ res1, err := Instantiate(env, T1, []Type{Typ[Int]}, false)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res2, err := Instantiate(env, T2, []Type{Typ[Int]}, false)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if res1 == res2 {
+ t.Errorf("instance from pkg1 (%s) is pointer-equivalent to instance from pkg2 (%s)", res1, res2)
+ }
+ if Identical(res1, res2) {
+ t.Errorf("instance from pkg1 (%s) is identical to instance from pkg2 (%s)", res1, res2)
+ }
+}
diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go
index e57158d2d50..340df51524b 100644
--- a/src/cmd/compile/internal/types2/interface.go
+++ b/src/cmd/compile/internal/types2/interface.go
@@ -11,6 +11,7 @@ import "cmd/compile/internal/syntax"
// An Interface represents an interface type.
type Interface struct {
+ check *Checker // for error reporting; nil once type set is computed
obj *TypeName // corresponding declared object; or nil (for better error messages)
methods []*Func // ordered list of explicitly declared methods
embeddeds []Type // ordered list of explicitly embedded elements
@@ -21,7 +22,7 @@ type Interface struct {
}
// typeSet returns the type set for interface t.
-func (t *Interface) typeSet() *_TypeSet { return computeInterfaceTypeSet(nil, nopos, t) }
+func (t *Interface) typeSet() *_TypeSet { return computeInterfaceTypeSet(t.check, nopos, t) }
// emptyInterface represents the empty interface
var emptyInterface = Interface{complete: true, tset: &topTypeSet}
@@ -198,7 +199,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
}
// All methods and embedded elements for this interface are collected;
- // i.e., this interface is may be used in a type set computation.
+ // i.e., this interface may be used in a type set computation.
ityp.complete = true
if len(ityp.methods) == 0 && len(ityp.embeddeds) == 0 {
@@ -214,7 +215,15 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
// Compute type set with a non-nil *Checker as soon as possible
// to report any errors. Subsequent uses of type sets will use
// this computed type set and won't need to pass in a *Checker.
- check.later(func() { computeInterfaceTypeSet(check, iface.Pos(), ityp) })
+ //
+ // Pin the checker to the interface type in the interim, in case the type set
+ // must be used before delayed funcs are processed (see issue #48234).
+ // TODO(rfindley): clean up use of *Checker with computeInterfaceTypeSet
+ ityp.check = check
+ check.later(func() {
+ computeInterfaceTypeSet(check, iface.Pos(), ityp)
+ ityp.check = nil
+ })
}
func flattenUnion(list []syntax.Expr, x syntax.Expr) []syntax.Expr {
diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go
index d0718e51e2d..0e7a2b70e2e 100644
--- a/src/cmd/compile/internal/types2/lookup.go
+++ b/src/cmd/compile/internal/types2/lookup.go
@@ -122,7 +122,7 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
seen[named] = true
// look for a matching attached method
- named.load()
+ named.resolve(nil)
if i, m := lookupMethod(named.methods, pkg, name); m != nil {
// potential match
// caution: method may not have a proper signature yet
@@ -321,10 +321,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
// both methods must have the same number of type parameters
ftyp := f.typ.(*Signature)
mtyp := m.typ.(*Signature)
- if ftyp.TParams().Len() != mtyp.TParams().Len() {
+ if ftyp.TypeParams().Len() != mtyp.TypeParams().Len() {
return m, f
}
- if !acceptMethodTypeParams && ftyp.TParams().Len() > 0 {
+ if !acceptMethodTypeParams && ftyp.TypeParams().Len() > 0 {
panic("method with type parameters")
}
@@ -334,7 +334,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
// TODO(gri) is this always correct? what about type bounds?
// (Alternative is to rename/subst type parameters and compare.)
u := newUnifier(true)
- u.x.init(ftyp.TParams().list())
+ u.x.init(ftyp.TypeParams().list())
if !u.unify(ftyp, mtyp) {
return m, f
}
@@ -373,10 +373,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
// both methods must have the same number of type parameters
ftyp := f.typ.(*Signature)
mtyp := m.typ.(*Signature)
- if ftyp.TParams().Len() != mtyp.TParams().Len() {
+ if ftyp.TypeParams().Len() != mtyp.TypeParams().Len() {
return m, f
}
- if !acceptMethodTypeParams && ftyp.TParams().Len() > 0 {
+ if !acceptMethodTypeParams && ftyp.TypeParams().Len() > 0 {
panic("method with type parameters")
}
@@ -387,17 +387,17 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
// In order to compare the signatures, substitute the receiver
// type parameters of ftyp with V's instantiation type arguments.
// This lazily instantiates the signature of method f.
- if Vn != nil && Vn.TParams().Len() > 0 {
+ if Vn != nil && Vn.TypeParams().Len() > 0 {
// Be careful: The number of type arguments may not match
// the number of receiver parameters. If so, an error was
// reported earlier but the length discrepancy is still
// here. Exit early in this case to prevent an assertion
// failure in makeSubstMap.
// TODO(gri) Can we avoid this check by fixing the lengths?
- if len(ftyp.RParams().list()) != Vn.targs.Len() {
+ if len(ftyp.RecvTypeParams().list()) != Vn.targs.Len() {
return
}
- ftyp = check.subst(nopos, ftyp, makeSubstMap(ftyp.RParams().list(), Vn.targs.list()), nil).(*Signature)
+ ftyp = check.subst(nopos, ftyp, makeSubstMap(ftyp.RecvTypeParams().list(), Vn.targs.list()), nil).(*Signature)
}
// If the methods have type parameters we don't care whether they
@@ -406,7 +406,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
// TODO(gri) is this always correct? what about type bounds?
// (Alternative is to rename/subst type parameters and compare.)
u := newUnifier(true)
- if ftyp.TParams().Len() > 0 {
+ if ftyp.TypeParams().Len() > 0 {
// We reach here only if we accept method type parameters.
// In this case, unification must consider any receiver
// and method type parameters as "free" type parameters.
@@ -416,9 +416,9 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
// unimplemented call so that we test this code if we
// enable method type parameters.
unimplemented()
- u.x.init(append(ftyp.RParams().list(), ftyp.TParams().list()...))
+ u.x.init(append(ftyp.RecvTypeParams().list(), ftyp.TypeParams().list()...))
} else {
- u.x.init(ftyp.RParams().list())
+ u.x.init(ftyp.RecvTypeParams().list())
}
if !u.unify(ftyp, mtyp) {
return m, f
diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go
index a76e69fcf17..c844012e39e 100644
--- a/src/cmd/compile/internal/types2/named.go
+++ b/src/cmd/compile/internal/types2/named.go
@@ -12,18 +12,18 @@ import (
// A Named represents a named (defined) type.
type Named struct {
check *Checker
- info typeInfo // for cycle detection
- obj *TypeName // corresponding declared object for declared types; placeholder for instantiated types
- orig *Named // original, uninstantiated type
- fromRHS Type // type (on RHS of declaration) this *Named type is derived from (for cycle reporting)
- underlying Type // possibly a *Named during setup; never a *Named once set up completely
- instPos *syntax.Pos // position information for lazy instantiation, or nil
- tparams *TParamList // type parameters, or nil
- targs *TypeList // type arguments (after instantiation), or nil
- methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily
-
- resolve func(*Named) ([]*TypeParam, Type, []*Func)
- once sync.Once
+ info typeInfo // for cycle detection
+ obj *TypeName // corresponding declared object for declared types; placeholder for instantiated types
+ orig *Named // original, uninstantiated type
+ fromRHS Type // type (on RHS of declaration) this *Named type is derived from (for cycle reporting)
+ underlying Type // possibly a *Named during setup; never a *Named once set up completely
+ tparams *TypeParamList // type parameters, or nil
+ targs *TypeList // type arguments (after instantiation), or nil
+ methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily
+
+ // resolver may be provided to lazily resolve type parameters, underlying, and methods.
+ resolver func(*Environment, *Named) (tparams *TypeParamList, underlying Type, methods []*Func)
+ once sync.Once // ensures that tparams, underlying, and methods are resolved before accessing
}
// NewNamed returns a new named type for the given type name, underlying type, and associated methods.
@@ -36,49 +36,28 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods)
}
-func (t *Named) load() *Named {
- // If t is an instantiated type, it derives its methods and tparams from its
- // base type. Since we expect type parameters and methods to be set after a
- // call to load, we must load the base and copy here.
- //
- // underlying is set when t is expanded.
- //
- // By convention, a type instance is loaded iff its tparams are set.
- if t.targs.Len() > 0 && t.tparams == nil {
- t.orig.load()
- t.tparams = t.orig.tparams
- t.methods = t.orig.methods
- }
- if t.resolve == nil {
+func (t *Named) resolve(env *Environment) *Named {
+ if t.resolver == nil {
return t
}
t.once.Do(func() {
- // TODO(mdempsky): Since we're passing t to resolve anyway
+ // TODO(mdempsky): Since we're passing t to the resolver anyway
// (necessary because types2 expects the receiver type for methods
// on defined interface types to be the Named rather than the
// underlying Interface), maybe it should just handle calling
- // SetTParams, SetUnderlying, and AddMethod instead? Those
- // methods would need to support reentrant calls though. It would
+ // SetTypeParams, SetUnderlying, and AddMethod instead? Those
+ // methods would need to support reentrant calls though. It would
// also make the API more future-proof towards further extensions
- // (like SetTParams).
-
- tparams, underlying, methods := t.resolve(t)
-
- switch underlying.(type) {
- case nil, *Named:
- panic("invalid underlying type")
- }
-
- t.tparams = bindTParams(tparams)
- t.underlying = underlying
- t.methods = methods
+ // (like SetTypeParams).
+ t.tparams, t.underlying, t.methods = t.resolver(env, t)
+ t.fromRHS = t.underlying // for cycle detection
})
return t
}
// newNamed is like NewNamed but with a *Checker receiver and additional orig argument.
-func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TParamList, methods []*Func) *Named {
+func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams *TypeParamList, methods []*Func) *Named {
typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods}
if typ.orig == nil {
typ.orig = typ
@@ -119,21 +98,21 @@ func (t *Named) Orig() *Named { return t.orig }
// TODO(gri) Come up with a better representation and API to distinguish
// between parameterized instantiated and non-instantiated types.
-// TParams returns the type parameters of the named type t, or nil.
+// TypeParams returns the type parameters of the named type t, or nil.
// The result is non-nil for an (originally) parameterized type even if it is instantiated.
-func (t *Named) TParams() *TParamList { return t.load().tparams }
+func (t *Named) TypeParams() *TypeParamList { return t.resolve(nil).tparams }
-// SetTParams sets the type parameters of the named type t.
-func (t *Named) SetTParams(tparams []*TypeParam) { t.load().tparams = bindTParams(tparams) }
+// SetTypeParams sets the type parameters of the named type t.
+func (t *Named) SetTypeParams(tparams []*TypeParam) { t.resolve(nil).tparams = bindTParams(tparams) }
-// TArgs returns the type arguments used to instantiate the named type t.
-func (t *Named) TArgs() *TypeList { return t.targs }
+// TypeArgs returns the type arguments used to instantiate the named type t.
+func (t *Named) TypeArgs() *TypeList { return t.targs }
// NumMethods returns the number of explicit methods whose receiver is named type t.
-func (t *Named) NumMethods() int { return len(t.load().methods) }
+func (t *Named) NumMethods() int { return len(t.resolve(nil).methods) }
// Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
-func (t *Named) Method(i int) *Func { return t.load().methods[i] }
+func (t *Named) Method(i int) *Func { return t.resolve(nil).methods[i] }
// SetUnderlying sets the underlying type and marks t as complete.
func (t *Named) SetUnderlying(underlying Type) {
@@ -143,18 +122,18 @@ func (t *Named) SetUnderlying(underlying Type) {
if _, ok := underlying.(*Named); ok {
panic("underlying type must not be *Named")
}
- t.load().underlying = underlying
+ t.resolve(nil).underlying = underlying
}
// AddMethod adds method m unless it is already in the method list.
func (t *Named) AddMethod(m *Func) {
- t.load()
+ t.resolve(nil)
if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 {
t.methods = append(t.methods, m)
}
}
-func (t *Named) Underlying() Type { return t.load().expand(nil).underlying }
+func (t *Named) Underlying() Type { return t.resolve(nil).underlying }
func (t *Named) String() string { return TypeString(t, nil) }
// ----------------------------------------------------------------------------
@@ -240,37 +219,36 @@ func (n *Named) setUnderlying(typ Type) {
}
}
-// expand ensures that the underlying type of n is instantiated.
+// expandNamed ensures that the underlying type of n is instantiated.
// The underlying type will be Typ[Invalid] if there was an error.
-func (n *Named) expand(typMap map[string]*Named) *Named {
- if n.instPos != nil {
- // n must be loaded before instantiation, in order to have accurate
- // tparams. This is done implicitly by the call to n.TParams, but making it
- // explicit is harmless: load is idempotent.
- n.load()
- var u Type
- if n.check.validateTArgLen(*n.instPos, n.tparams.Len(), n.targs.Len()) {
- if typMap == nil {
- if n.check != nil {
- typMap = n.check.typMap
- } else {
- // If we're instantiating lazily, we might be outside the scope of a
- // type-checking pass. In that case we won't have a pre-existing
- // typMap, but don't want to create a duplicate of the current instance
- // in the process of expansion.
- h := typeHash(n.orig, n.targs.list())
- typMap = map[string]*Named{h: n}
- }
+func expandNamed(env *Environment, n *Named, instPos syntax.Pos) (*TypeParamList, Type, []*Func) {
+ n.orig.resolve(env)
+
+ var u Type
+ if n.check.validateTArgLen(instPos, n.orig.tparams.Len(), n.targs.Len()) {
+ // TODO(rfindley): handling an optional Checker and Environment here (and
+ // in subst) feels overly complicated. Can we simplify?
+ if env == nil {
+ if n.check != nil {
+ env = n.check.conf.Environment
+ } else {
+ // If we're instantiating lazily, we might be outside the scope of a
+ // type-checking pass. In that case we won't have a pre-existing
+ // environment, but don't want to create a duplicate of the current
+ // instance in the process of expansion.
+ env = NewEnvironment()
}
- u = n.check.subst(*n.instPos, n.orig.underlying, makeSubstMap(n.TParams().list(), n.targs.list()), typMap)
- } else {
- u = Typ[Invalid]
+ h := env.TypeHash(n.orig, n.targs.list())
+ // add the instance to the environment to avoid infinite recursion.
+ // addInstance may return a different, existing instance, but we
+ // shouldn't return that instance from expand.
+ env.typeForHash(h, n)
}
- n.underlying = u
- n.fromRHS = u
- n.instPos = nil
+ u = n.check.subst(instPos, n.orig.underlying, makeSubstMap(n.orig.tparams.list(), n.targs.list()), env)
+ } else {
+ u = Typ[Invalid]
}
- return n
+ return n.orig.tparams, u, n.orig.methods
}
// safeUnderlying returns the underlying of typ without expanding instances, to
@@ -279,7 +257,7 @@ func (n *Named) expand(typMap map[string]*Named) *Named {
// TODO(rfindley): eliminate this function or give it a better name.
func safeUnderlying(typ Type) Type {
if t, _ := typ.(*Named); t != nil {
- return t.load().underlying
+ return t.resolve(nil).underlying
}
return typ.Underlying()
}
diff --git a/src/cmd/compile/internal/types2/object.go b/src/cmd/compile/internal/types2/object.go
index a3f5f913aa5..540cb3f44f8 100644
--- a/src/cmd/compile/internal/types2/object.go
+++ b/src/cmd/compile/internal/types2/object.go
@@ -278,9 +278,21 @@ func NewTypeName(pos syntax.Pos, pkg *Package, name string, typ Type) *TypeName
// NewTypeNameLazy returns a new defined type like NewTypeName, but it
// lazily calls resolve to finish constructing the Named object.
-func NewTypeNameLazy(pos syntax.Pos, pkg *Package, name string, resolve func(named *Named) (tparams []*TypeParam, underlying Type, methods []*Func)) *TypeName {
+func NewTypeNameLazy(pos syntax.Pos, pkg *Package, name string, load func(named *Named) (tparams []*TypeParam, underlying Type, methods []*Func)) *TypeName {
obj := NewTypeName(pos, pkg, name, nil)
- NewNamed(obj, nil, nil).resolve = resolve
+
+ resolve := func(_ *Environment, t *Named) (*TypeParamList, Type, []*Func) {
+ tparams, underlying, methods := load(t)
+
+ switch underlying.(type) {
+ case nil, *Named:
+ panic(fmt.Sprintf("invalid underlying type %T", t.underlying))
+ }
+
+ return bindTParams(tparams), underlying, methods
+ }
+
+ NewNamed(obj, nil, nil).resolver = resolve
return obj
}
@@ -475,8 +487,8 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
if _, ok := typ.(*Basic); ok {
return
}
- if named, _ := typ.(*Named); named != nil && named.TParams().Len() > 0 {
- newTypeWriter(buf, qf).tParamList(named.TParams().list())
+ if named, _ := typ.(*Named); named != nil && named.TypeParams().Len() > 0 {
+ newTypeWriter(buf, qf).tParamList(named.TypeParams().list())
}
if tname.IsAlias() {
buf.WriteString(" =")
diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go
index 3ccafef990c..74ad3da72cb 100644
--- a/src/cmd/compile/internal/types2/predicates.go
+++ b/src/cmd/compile/internal/types2/predicates.go
@@ -21,7 +21,7 @@ func isNamed(typ Type) bool {
func isGeneric(typ Type) bool {
// A parameterized type is only instantiated if it doesn't have an instantiation already.
named, _ := typ.(*Named)
- return named != nil && named.obj != nil && named.targs == nil && named.TParams() != nil
+ return named != nil && named.obj != nil && named.targs == nil && named.TypeParams() != nil
}
func is(typ Type, what BasicInfo) bool {
@@ -220,11 +220,18 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
// parameter names.
if y, ok := y.(*Signature); ok {
return x.variadic == y.variadic &&
- identicalTParams(x.TParams().list(), y.TParams().list(), cmpTags, p) &&
+ identicalTParams(x.TypeParams().list(), y.TypeParams().list(), cmpTags, p) &&
identical(x.params, y.params, cmpTags, p) &&
identical(x.results, y.results, cmpTags, p)
}
+ case *Union:
+ if y, _ := y.(*Union); y != nil {
+ xset := computeUnionTypeSet(nil, nopos, x)
+ yset := computeUnionTypeSet(nil, nopos, y)
+ return xset.terms.equal(yset.terms)
+ }
+
case *Interface:
// Two interface types are identical if they describe the same type sets.
// With the existing implementation restriction, this simplifies to:
@@ -302,11 +309,8 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
// Two named types are identical if their type names originate
// in the same type declaration.
if y, ok := y.(*Named); ok {
- x.expand(nil)
- y.expand(nil)
-
- xargs := x.TArgs().list()
- yargs := y.TArgs().list()
+ xargs := x.TypeArgs().list()
+ yargs := y.TypeArgs().list()
if len(xargs) != len(yargs) {
return false
diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go
index a7d0db624ce..e3186f5eed2 100644
--- a/src/cmd/compile/internal/types2/signature.go
+++ b/src/cmd/compile/internal/types2/signature.go
@@ -19,13 +19,13 @@ type Signature struct {
// and store it in the Func Object) because when type-checking a function
// literal we call the general type checker which returns a general Type.
// We then unpack the *Signature and use the scope for the literal body.
- rparams *TParamList // receiver type parameters from left to right, or nil
- tparams *TParamList // type parameters from left to right, or nil
- scope *Scope // function scope, present for package-local signatures
- recv *Var // nil if not a method
- params *Tuple // (incoming) parameters from left to right; or nil
- results *Tuple // (outgoing) results from left to right; or nil
- variadic bool // true if the last parameter's type is of the form ...T (or string, for append built-in only)
+ rparams *TypeParamList // receiver type parameters from left to right, or nil
+ tparams *TypeParamList // type parameters from left to right, or nil
+ scope *Scope // function scope, present for package-local signatures
+ recv *Var // nil if not a method
+ params *Tuple // (incoming) parameters from left to right; or nil
+ results *Tuple // (outgoing) results from left to right; or nil
+ variadic bool // true if the last parameter's type is of the form ...T (or string, for append built-in only)
}
// NewSignature returns a new function type for the given receiver, parameters,
@@ -53,17 +53,17 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
// contain methods whose receiver type is a different interface.
func (s *Signature) Recv() *Var { return s.recv }
-// TParams returns the type parameters of signature s, or nil.
-func (s *Signature) TParams() *TParamList { return s.tparams }
+// TypeParams returns the type parameters of signature s, or nil.
+func (s *Signature) TypeParams() *TypeParamList { return s.tparams }
-// SetTParams sets the type parameters of signature s.
-func (s *Signature) SetTParams(tparams []*TypeParam) { s.tparams = bindTParams(tparams) }
+// SetTypeParams sets the type parameters of signature s.
+func (s *Signature) SetTypeParams(tparams []*TypeParam) { s.tparams = bindTParams(tparams) }
-// RParams returns the receiver type parameters of signature s, or nil.
-func (s *Signature) RParams() *TParamList { return s.rparams }
+// RecvTypeParams returns the receiver type parameters of signature s, or nil.
+func (s *Signature) RecvTypeParams() *TypeParamList { return s.rparams }
-// SetRParams sets the receiver type params of signature s.
-func (s *Signature) SetRParams(rparams []*TypeParam) { s.rparams = bindTParams(rparams) }
+// SetRecvTypeParams sets the receiver type params of signature s.
+func (s *Signature) SetRecvTypeParams(rparams []*TypeParam) { s.rparams = bindTParams(rparams) }
// Params returns the parameters of signature s, or nil.
func (s *Signature) Params() *Tuple { return s.params }
@@ -133,19 +133,19 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
// again when we type-check the signature.
// TODO(gri) maybe the receiver should be marked as invalid instead?
if recv, _ := check.genericType(rname, false).(*Named); recv != nil {
- recvTParams = recv.TParams().list()
+ recvTParams = recv.TypeParams().list()
}
}
// provide type parameter bounds
// - only do this if we have the right number (otherwise an error is reported elsewhere)
- if sig.RParams().Len() == len(recvTParams) {
+ if sig.RecvTypeParams().Len() == len(recvTParams) {
// We have a list of *TypeNames but we need a list of Types.
- list := make([]Type, sig.RParams().Len())
- for i, t := range sig.RParams().list() {
+ list := make([]Type, sig.RecvTypeParams().Len())
+ for i, t := range sig.RecvTypeParams().list() {
list[i] = t
}
smap := makeSubstMap(recvTParams, list)
- for i, tpar := range sig.RParams().list() {
+ for i, tpar := range sig.RecvTypeParams().list() {
bound := recvTParams[i].bound
// bound is (possibly) parameterized in the context of the
// receiver type declaration. Substitute parameters for the
@@ -210,10 +210,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
var err string
switch T := rtyp.(type) {
case *Named:
- T.expand(nil)
+ T.resolve(check.conf.Environment)
// The receiver type may be an instantiated type referred to
// by an alias (which cannot have receiver parameters for now).
- if T.TArgs() != nil && sig.RParams() == nil {
+ if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
break
}
diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go
index 5be369d8438..a7f1185fa89 100644
--- a/src/cmd/compile/internal/types2/sizeof_test.go
+++ b/src/cmd/compile/internal/types2/sizeof_test.go
@@ -28,10 +28,10 @@ func TestSizeof(t *testing.T) {
{Tuple{}, 12, 24},
{Signature{}, 28, 56},
{Union{}, 16, 32},
- {Interface{}, 40, 80},
+ {Interface{}, 44, 88},
{Map{}, 16, 32},
{Chan{}, 12, 24},
- {Named{}, 72, 136},
+ {Named{}, 68, 128},
{TypeParam{}, 28, 48},
{term{}, 12, 24},
{top{}, 0, 0},
diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go
index c67538d4f0f..87c1d7872bf 100644
--- a/src/cmd/compile/internal/types2/subst.go
+++ b/src/cmd/compile/internal/types2/subst.go
@@ -6,10 +6,7 @@
package types2
-import (
- "bytes"
- "cmd/compile/internal/syntax"
-)
+import "cmd/compile/internal/syntax"
type substMap map[*TypeParam]Type
@@ -40,8 +37,8 @@ func (m substMap) lookup(tpar *TypeParam) Type {
// incoming type. If a substitution took place, the result type is different
// from the incoming type.
//
-// If the given typMap is non-nil, it is used in lieu of check.typMap.
-func (check *Checker) subst(pos syntax.Pos, typ Type, smap substMap, typMap map[string]*Named) Type {
+// If the given environment is non-nil, it is used in lieu of check.env.
+func (check *Checker) subst(pos syntax.Pos, typ Type, smap substMap, env *Environment) Type {
if smap.empty() {
return typ
}
@@ -61,27 +58,27 @@ func (check *Checker) subst(pos syntax.Pos, typ Type, smap substMap, typMap map[
if check != nil {
subst.check = check
- if typMap == nil {
- typMap = check.typMap
+ if env == nil {
+ env = check.conf.Environment
}
}
- if typMap == nil {
+ if env == nil {
// If we don't have a *Checker and its global type map,
// use a local version. Besides avoiding duplicate work,
// the type map prevents infinite recursive substitution
// for recursive types (example: type T[P any] *T[P]).
- typMap = make(map[string]*Named)
+ env = NewEnvironment()
}
- subst.typMap = typMap
+ subst.env = env
return subst.typ(typ)
}
type subster struct {
- pos syntax.Pos
- smap substMap
- check *Checker // nil if called via Instantiate
- typMap map[string]*Named
+ pos syntax.Pos
+ smap substMap
+ check *Checker // nil if called via Instantiate
+ env *Environment
}
func (subst *subster) typ(typ Type) Type {
@@ -182,13 +179,19 @@ func (subst *subster) typ(typ Type) Type {
}
}
- if t.TParams().Len() == 0 {
+ // subst is called by expandNamed, so in this function we need to be
+ // careful not to call any methods that would cause t to be expanded: doing
+ // so would result in deadlock.
+ //
+ // So we call t.orig.TypeParams() rather than t.TypeParams() here and
+ // below.
+ if t.orig.TypeParams().Len() == 0 {
dump(">>> %s is not parameterized", t)
return t // type is not parameterized
}
var newTArgs []Type
- assert(t.targs.Len() == t.TParams().Len())
+ assert(t.targs.Len() == t.orig.TypeParams().Len())
// already instantiated
dump(">>> %s already instantiated", t)
@@ -201,7 +204,7 @@ func (subst *subster) typ(typ Type) Type {
if new_targ != targ {
dump(">>> substituted %d targ %s => %s", i, targ, new_targ)
if newTArgs == nil {
- newTArgs = make([]Type, t.TParams().Len())
+ newTArgs = make([]Type, t.orig.TypeParams().Len())
copy(newTArgs, t.targs.list())
}
newTArgs[i] = new_targ
@@ -214,32 +217,29 @@ func (subst *subster) typ(typ Type) Type {
}
// before creating a new named type, check if we have this one already
- h := typeHash(t, newTArgs)
+ h := subst.env.TypeHash(t.orig, newTArgs)
dump(">>> new type hash: %s", h)
- if named, found := subst.typMap[h]; found {
+ if named := subst.env.typeForHash(h, nil); named != nil {
dump(">>> found %s", named)
return named
}
- // Create a new named type and populate typMap to avoid endless recursion.
- // The position used here is irrelevant because validation only occurs on t
- // (we don't call validType on named), but we use subst.pos to help with
- // debugging.
- tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil)
- t.load()
- // It's ok to provide a nil *Checker because the newly created type
- // doesn't need to be (lazily) expanded; it's expanded below.
- named := (*Checker)(nil).newNamed(tname, t.orig, nil, t.tparams, t.methods) // t is loaded, so tparams and methods are available
- named.targs = NewTypeList(newTArgs)
- subst.typMap[h] = named
- t.expand(subst.typMap) // must happen after typMap update to avoid infinite recursion
-
- // do the substitution
- dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTArgs)
- named.underlying = subst.typOrNil(t.underlying)
- dump(">>> underlying: %v", named.underlying)
+ t.orig.resolve(subst.env)
+ // Create a new instance and populate the environment to avoid endless
+ // recursion. The position used here is irrelevant because validation only
+ // occurs on t (we don't call validType on named), but we use subst.pos to
+ // help with debugging.
+ named := subst.check.instance(subst.pos, t.orig, newTArgs, subst.env).(*Named)
+ // TODO(rfindley): we probably don't need to resolve here. Investigate if
+ // this can be removed.
+ named.resolve(subst.env)
assert(named.underlying != nil)
- named.fromRHS = named.underlying // for consistency, though no cycle detection is necessary
+
+ // Note that if we were to expose substitution more generally (not just in
+ // the context of a declaration), we'd have to substitute in
+ // named.underlying as well.
+ //
+ // But this is unnecessary for now.
return named
@@ -253,35 +253,6 @@ func (subst *subster) typ(typ Type) Type {
return typ
}
-// typeHash returns a string representation of typ, which can be used as an exact
-// type hash: types that are identical produce identical string representations.
-// If typ is a *Named type and targs is not empty, typ is printed as if it were
-// instantiated with targs.
-func typeHash(typ Type, targs []Type) string {
- assert(typ != nil)
- var buf bytes.Buffer
-
- h := newTypeHasher(&buf)
- if named, _ := typ.(*Named); named != nil && len(targs) > 0 {
- // Don't use WriteType because we need to use the provided targs
- // and not any targs that might already be with the *Named type.
- h.typeName(named.obj)
- h.typeList(targs)
- } else {
- assert(targs == nil)
- h.typ(typ)
- }
-
- if debug {
- // there should be no instance markers in type hashes
- for _, b := range buf.Bytes() {
- assert(b != instanceMarker)
- }
- }
-
- return buf.String()
-}
-
// typOrNil is like typ but if the argument is nil it is replaced with Typ[Invalid].
// A nil type may appear in pathological cases such as type T[P any] []func(_ T([]_))
// where an array/slice element is accessed before it is set up.
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43527.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43527.go2
new file mode 100644
index 00000000000..e4bcee51fe5
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43527.go2
@@ -0,0 +1,16 @@
+// Copyright 2021 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 p
+
+const L = 10
+
+type (
+ _ [L]struct{}
+ _ [A /* ERROR undeclared name A for array length */ ]struct{}
+ _ [B /* ERROR not an expression */ ]struct{}
+ _[A any] struct{}
+
+ B int
+)
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47887.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47887.go2
new file mode 100644
index 00000000000..4c4fc2fda8f
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47887.go2
@@ -0,0 +1,28 @@
+// Copyright 2021 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 p
+
+type Fooer[t any] interface {
+ foo(Barer[t])
+}
+type Barer[t any] interface {
+ bar(Bazer[t])
+}
+type Bazer[t any] interface {
+ Fooer[t]
+ baz(t)
+}
+
+type Int int
+
+func (n Int) baz(int) {}
+func (n Int) foo(b Barer[int]) { b.bar(n) }
+
+type F[t any] interface { f(G[t]) }
+type G[t any] interface { g(H[t]) }
+type H[t any] interface { F[t] }
+
+type T struct{}
+func (n T) f(b G[T]) { b.g(n) }
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2
index 56e90942ab6..2c4b6610fec 100644
--- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2
@@ -5,4 +5,4 @@
package p
// don't crash
-func T /* ERROR missing */ [P /* ERROR named */ ] m /* ERROR m */ () /* ERROR \) */ { /* ERROR { */ } /* ERROR } */
+func T /* ERROR missing */ [P] /* ERROR missing */ m /* ERROR unexpected */ () /* ERROR \) */ { /* ERROR { */ } /* ERROR } */
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48234.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48234.go2
new file mode 100644
index 00000000000..e069930c42d
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48234.go2
@@ -0,0 +1,10 @@
+// Copyright 2021 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 p
+
+var _ = interface{
+ m()
+ m /* ERROR "duplicate method" */ ()
+}(nil)
diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go
index ca5ecdc4344..400d6f71287 100644
--- a/src/cmd/compile/internal/types2/type.go
+++ b/src/cmd/compile/internal/types2/type.go
@@ -115,7 +115,7 @@ func asInterface(t Type) *Interface {
func asNamed(t Type) *Named {
e, _ := t.(*Named)
if e != nil {
- e.expand(nil)
+ e.resolve(nil)
}
return e
}
diff --git a/src/cmd/compile/internal/types2/typelists.go b/src/cmd/compile/internal/types2/typelists.go
index f313ea310e9..ababe85909d 100644
--- a/src/cmd/compile/internal/types2/typelists.go
+++ b/src/cmd/compile/internal/types2/typelists.go
@@ -6,20 +6,20 @@ package types2
import "bytes"
-// TParamList holds a list of type parameters.
-type TParamList struct{ tparams []*TypeParam }
+// TypeParamList holds a list of type parameters.
+type TypeParamList struct{ tparams []*TypeParam }
// Len returns the number of type parameters in the list.
// It is safe to call on a nil receiver.
-func (l *TParamList) Len() int { return len(l.list()) }
+func (l *TypeParamList) Len() int { return len(l.list()) }
// At returns the i'th type parameter in the list.
-func (l *TParamList) At(i int) *TypeParam { return l.tparams[i] }
+func (l *TypeParamList) At(i int) *TypeParam { return l.tparams[i] }
// list is for internal use where we expect a []*TypeParam.
// TODO(rfindley): list should probably be eliminated: we can pass around a
-// TParamList instead.
-func (l *TParamList) list() []*TypeParam {
+// TypeParamList instead.
+func (l *TypeParamList) list() []*TypeParam {
if l == nil {
return nil
}
@@ -66,7 +66,7 @@ func (l *TypeList) String() string {
// ----------------------------------------------------------------------------
// Implementation
-func bindTParams(list []*TypeParam) *TParamList {
+func bindTParams(list []*TypeParam) *TypeParamList {
if len(list) == 0 {
return nil
}
@@ -76,5 +76,5 @@ func bindTParams(list []*TypeParam) *TParamList {
}
typ.index = i
}
- return &TParamList{tparams: list}
+ return &TypeParamList{tparams: list}
}
diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go
index 445337fee88..505596f5719 100644
--- a/src/cmd/compile/internal/types2/typeparam.go
+++ b/src/cmd/compile/internal/types2/typeparam.go
@@ -29,18 +29,22 @@ type TypeParam struct {
func (t *TypeParam) Obj() *TypeName { return t.obj }
// NewTypeParam returns a new TypeParam. Type parameters may be set on a Named
-// or Signature type by calling SetTParams. Setting a type parameter on more
+// or Signature type by calling SetTypeParams. Setting a type parameter on more
// than one type will result in a panic.
//
-// The bound argument can be nil, and set later via SetBound.
-func (check *Checker) NewTypeParam(obj *TypeName, bound Type) *TypeParam {
+// The constraint argument can be nil, and set later via SetConstraint.
+func NewTypeParam(obj *TypeName, constraint Type) *TypeParam {
+ return (*Checker)(nil).newTypeParam(obj, constraint)
+}
+
+func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
// Always increment lastID, even if it is not used.
id := nextID()
if check != nil {
check.nextID++
id = check.nextID
}
- typ := &TypeParam{check: check, id: id, obj: obj, index: -1, bound: bound}
+ typ := &TypeParam{check: check, id: id, obj: obj, index: -1, bound: constraint}
if obj.typ == nil {
obj.typ = typ
}
diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go
index 6083955306b..bdafcf883db 100644
--- a/src/cmd/compile/internal/types2/typestring.go
+++ b/src/cmd/compile/internal/types2/typestring.go
@@ -8,7 +8,7 @@ package types2
import (
"bytes"
- "fmt"
+ "strconv"
"unicode/utf8"
)
@@ -63,32 +63,45 @@ func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
newTypeWriter(buf, qf).signature(sig)
}
-// instanceMarker is the prefix for an instantiated type in unexpanded form.
-const instanceMarker = '#'
-
type typeWriter struct {
buf *bytes.Buffer
seen map[Type]bool
qf Qualifier
- hash bool
+ env *Environment // if non-nil, we are type hashing
}
func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
- return &typeWriter{buf, make(map[Type]bool), qf, false}
+ return &typeWriter{buf, make(map[Type]bool), qf, nil}
}
-func newTypeHasher(buf *bytes.Buffer) *typeWriter {
- return &typeWriter{buf, make(map[Type]bool), nil, true}
+func newTypeHasher(buf *bytes.Buffer, env *Environment) *typeWriter {
+ assert(env != nil)
+ return &typeWriter{buf, make(map[Type]bool), nil, env}
+}
+
+func (w *typeWriter) byte(b byte) {
+ if w.env != nil {
+ if b == ' ' {
+ b = '#'
+ }
+ w.buf.WriteByte(b)
+ return
+ }
+ w.buf.WriteByte(b)
+ if b == ',' || b == ';' {
+ w.buf.WriteByte(' ')
+ }
+}
+
+func (w *typeWriter) string(s string) {
+ w.buf.WriteString(s)
}
-func (w *typeWriter) byte(b byte) { w.buf.WriteByte(b) }
-func (w *typeWriter) string(s string) { w.buf.WriteString(s) }
-func (w *typeWriter) writef(format string, args ...interface{}) { fmt.Fprintf(w.buf, format, args...) }
func (w *typeWriter) error(msg string) {
- if w.hash {
+ if w.env != nil {
panic(msg)
}
- w.string("<" + msg + ">")
+ w.buf.WriteString("<" + msg + ">")
}
func (w *typeWriter) typ(typ Type) {
@@ -115,7 +128,9 @@ func (w *typeWriter) typ(typ Type) {
w.string(t.name)
case *Array:
- w.writef("[%d]", t.len)
+ w.byte('[')
+ w.string(strconv.FormatInt(t.len, 10))
+ w.byte(']')
w.typ(t.elem)
case *Slice:
@@ -126,7 +141,7 @@ func (w *typeWriter) typ(typ Type) {
w.string("struct{")
for i, f := range t.fields {
if i > 0 {
- w.string("; ")
+ w.byte(';')
}
// This doesn't do the right thing for embedded type
// aliases where we should print the alias name, not
@@ -137,7 +152,11 @@ func (w *typeWriter) typ(typ Type) {
}
w.typ(f.typ)
if tag := t.Tag(i); tag != "" {
- w.writef(" %q", tag)
+ w.byte(' ')
+ // TODO(gri) If tag contains blanks, replacing them with '#'
+ // in Environment.TypeHash may produce another tag
+ // accidentally.
+ w.string(strconv.Quote(tag))
}
}
w.byte('}')
@@ -175,7 +194,7 @@ func (w *typeWriter) typ(typ Type) {
first := true
for _, m := range t.methods {
if !first {
- w.string("; ")
+ w.byte(';')
}
first = false
w.string(m.name)
@@ -183,7 +202,7 @@ func (w *typeWriter) typ(typ Type) {
}
for _, typ := range t.embeddeds {
if !first {
- w.string("; ")
+ w.byte(';')
}
first = false
w.typ(typ)
@@ -223,20 +242,14 @@ func (w *typeWriter) typ(typ Type) {
}
case *Named:
- // Instance markers indicate unexpanded instantiated
- // types. Write them to aid debugging, but don't write
- // them when we need an instance hash: whether a type
- // is fully expanded or not doesn't matter for identity.
- if !w.hash && t.instPos != nil {
- w.byte(instanceMarker)
- }
+ w.typePrefix(t)
w.typeName(t.obj)
if t.targs != nil {
// instantiated type
w.typeList(t.targs.list())
- } else if !w.hash && t.TParams().Len() != 0 { // For type hashing, don't need to format the TParams
+ } else if w.env == nil && t.TypeParams().Len() != 0 { // For type hashing, don't need to format the TParams
// parameterized type
- w.tParamList(t.TParams().list())
+ w.tParamList(t.TypeParams().list())
}
case *TypeParam:
@@ -263,11 +276,20 @@ func (w *typeWriter) typ(typ Type) {
}
}
+// If w.env is non-nil, typePrefix writes a unique prefix for the named type t
+// based on the types already observed by w.env. If w.env is nil, it does
+// nothing.
+func (w *typeWriter) typePrefix(t *Named) {
+ if w.env != nil {
+ w.string(strconv.Itoa(w.env.idForType(t)))
+ }
+}
+
func (w *typeWriter) typeList(list []Type) {
w.byte('[')
for i, typ := range list {
if i > 0 {
- w.string(", ")
+ w.byte(',')
}
w.typ(typ)
}
@@ -291,7 +313,7 @@ func (w *typeWriter) tParamList(list []*TypeParam) {
w.byte(' ')
w.typ(prev)
}
- w.string(", ")
+ w.byte(',')
}
prev = tpar.bound
w.typ(tpar)
@@ -308,31 +330,6 @@ func (w *typeWriter) typeName(obj *TypeName) {
writePackage(w.buf, obj.pkg, w.qf)
}
w.string(obj.name)
-
- if w.hash {
- // For local defined types, use the (original!) TypeName's scope
- // numbers to disambiguate.
- if typ, _ := obj.typ.(*Named); typ != nil {
- // TODO(gri) Figure out why typ.orig != typ.orig.orig sometimes
- // and whether the loop can iterate more than twice.
- // (It seems somehow connected to instance types.)
- for typ.orig != typ {
- typ = typ.orig
- }
- w.writeScopeNumbers(typ.obj.parent)
- }
- }
-}
-
-// writeScopeNumbers writes the number sequence for this scope to buf
-// in the form ".i.j.k" where i, j, k, etc. stand for scope numbers.
-// If a scope is nil or has no parent (such as a package scope), nothing
-// is written.
-func (w *typeWriter) writeScopeNumbers(s *Scope) {
- if s != nil && s.number > 0 {
- w.writeScopeNumbers(s.parent)
- w.writef(".%d", s.number)
- }
}
func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
@@ -340,10 +337,10 @@ func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
if tup != nil {
for i, v := range tup.vars {
if i > 0 {
- w.string(", ")
+ w.byte(',')
}
// parameter names are ignored for type identity and thus type hashes
- if !w.hash && v.name != "" {
+ if w.env == nil && v.name != "" {
w.string(v.name)
w.byte(' ')
}
@@ -371,8 +368,8 @@ func (w *typeWriter) tuple(tup *Tuple, variadic bool) {
}
func (w *typeWriter) signature(sig *Signature) {
- if sig.TParams().Len() != 0 {
- w.tParamList(sig.TParams().list())
+ if sig.TypeParams().Len() != 0 {
+ w.tParamList(sig.TypeParams().list())
}
w.tuple(sig.params, sig.variadic)
@@ -384,7 +381,7 @@ func (w *typeWriter) signature(sig *Signature) {
}
w.byte(' ')
- if n == 1 && (w.hash || sig.results.vars[0].name == "") {
+ if n == 1 && (w.env != nil || sig.results.vars[0].name == "") {
// single unnamed result (if type hashing, name must be ignored)
w.typ(sig.results.vars[0].typ)
return
diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go
index f3db3bbba93..5aacb94a605 100644
--- a/src/cmd/compile/internal/types2/typexpr.go
+++ b/src/cmd/compile/internal/types2/typexpr.go
@@ -428,6 +428,14 @@ func (check *Checker) instantiatedType(x syntax.Expr, targsx []syntax.Expr, def
// and returns the constant length >= 0, or a value < 0
// to indicate an error (and thus an unknown length).
func (check *Checker) arrayLength(e syntax.Expr) int64 {
+ // If e is an undeclared identifier, the array declaration might be an
+ // attempt at a parameterized type declaration with missing constraint.
+ // Provide a better error message than just "undeclared name: X".
+ if name, _ := e.(*syntax.Name); name != nil && check.lookup(name.Value) == nil {
+ check.errorf(name, "undeclared name %s for array length", name.Value)
+ return -1
+ }
+
var x operand
check.expr(&x, e)
if x.mode != constant_ {
@@ -436,6 +444,7 @@ func (check *Checker) arrayLength(e syntax.Expr) int64 {
}
return -1
}
+
if isUntyped(x.typ) || isInteger(x.typ) {
if val := constant.ToInt(x.val); val.Kind() == constant.Int {
if representableConst(val, check, Typ[Int], nil) {
@@ -447,6 +456,7 @@ func (check *Checker) arrayLength(e syntax.Expr) int64 {
}
}
}
+
check.errorf(&x, "array length %s must be integer", &x)
return -1
}
diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go
index a1e5b3679bf..bb69f0d27bc 100644
--- a/src/cmd/compile/internal/types2/unify.go
+++ b/src/cmd/compile/internal/types2/unify.go
@@ -428,9 +428,6 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool {
case *Named:
if y, ok := y.(*Named); ok {
- x.expand(nil)
- y.expand(nil)
-
xargs := x.targs.list()
yargs := y.targs.list()
diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go
index a615b4c8760..af3ab973259 100644
--- a/src/cmd/compile/internal/types2/universe.go
+++ b/src/cmd/compile/internal/types2/universe.go
@@ -88,7 +88,7 @@ func defPredeclaredTypes() {
res := NewVar(nopos, nil, "", Typ[String])
sig := NewSignature(nil, nil, NewTuple(res), false)
err := NewFunc(nopos, nil, "Error", sig)
- ityp := &Interface{obj, []*Func{err}, nil, nil, true, nil}
+ ityp := &Interface{nil, obj, []*Func{err}, nil, nil, true, nil}
computeInterfaceTypeSet(nil, nopos, ityp) // prevent races due to lazy computation of tset
typ := NewNamed(obj, ityp, nil)
sig.recv = NewVar(nopos, nil, "", typ)
@@ -99,7 +99,7 @@ func defPredeclaredTypes() {
{
obj := NewTypeName(nopos, nil, "comparable", nil)
obj.setColor(black)
- ityp := &Interface{obj, nil, nil, nil, true, &_TypeSet{true, nil, allTermlist}}
+ ityp := &Interface{nil, obj, nil, nil, nil, true, &_TypeSet{true, nil, allTermlist}}
NewNamed(obj, ityp, nil)
def(obj)
}