]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] all: merge dev.regabi (ec741b0) into dev.typeparams
authorRuss Cox <rsc@golang.org>
Tue, 22 Dec 2020 22:08:15 +0000 (17:08 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 22 Dec 2020 22:08:17 +0000 (17:08 -0500)
Conflicts:

* src/cmd/compile/internal/gc/main.go

Merge List:

* 2020-12-22 ec741b0447 [dev.regabi] all: merge master (c9fb4eb) into dev.regabi
* 2020-12-22 acc32ea124 [dev.regabi] codereview.cfg: add config for dev.regabi
* 2020-12-22 c9fb4eb0a2 cmd/link: handle grouped resource sections
* 2020-12-22 c40934b33d [dev.regabi] cmd/compile: adjust one case in walkexpr
* 2020-12-22 280e7fd1ee [dev.regabi] cmd/compile: only access Func method on concrete types
* 2020-12-22 51ba53f5c2 [dev.regabi] cmd/compile: separate misc for gc split
* 2020-12-22 572f168ed2 [dev.regabi] cmd/compile: separate various from Main
* 2020-12-22 3b12c6dc08 [dev.regabi] cmd/compile: separate typecheck more cleanly
* 2020-12-22 7c8f5356ab [dev.regabi] cmd/compile: separate dowidth better
* 2020-12-22 c06a354bcc test: trigger SIGSEGV instead of SIGTRAP in issue11656.go
* 2020-12-22 0aa9b4709a cmd/pack: r command create output file if not exist
* 2020-12-22 cb28c96be8 [dev.regabi] cmd/compile,cmd/link: initial support for ABI wrappers
* 2020-12-22 c8610e4700 [dev.regabi] cmd/compile: add ir.BasicLit to represent literals
* 2020-12-22 3512cde10a [dev.regabi] cmd/compile: stop reusing Ntype for OSLICELIT length
* 2020-12-22 2755361e6a [dev.regabi] cmd/compile: change noder.declNames to returns ir.Names
* 2020-12-22 301af2cb71 [dev.regabi] runtime/race: adjust test pattern match for ABI wrapper
* 2020-12-22 4d27c4c223 runtime: correct error handling in several FreeBSD syscall wrappers
* 2020-12-22 9b6147120a cmd/pack: treat compiler's -linkobj output as "compiler object"
* 2020-12-22 306b2451c8 [dev.regabi] runtime: fix ABI targets in runtime.panic{Index,Slice} shims
* 2020-12-21 bc7e4d9257 syscall: don't generate ptrace on iOS
* 2020-12-21 94cfeca0a5 [dev.regabi] cmd/compile: stop using ONONAME with Name
* 2020-12-21 cb4898a77d [dev.regabi] cmd/compile: simplify declaration importing
* 2020-12-21 06915ac14d [dev.regabi] cmd/compile: move itabname call out of implements
* 2020-12-21 6cff874c47 runtime/metrics: add Read examples
* 2020-12-21 8438a5779b runtime: use _exit on darwin
* 2020-12-21 cb95819cf6 runtime: detect netbsd netpoll overrun in sysmon
* 2020-12-21 53c984d976 runtime: skip wakep call in wakeNetPoller on Plan 9
* 2020-12-21 9abbe27710 test: skip issue11656.go on mips/mips64/ppc64

Change-Id: Ia12a1892195f5e08bb41465374124c71a1a135f6

385 files changed:
codereview.cfg
src/cmd/compile/fmtmap_test.go
src/cmd/compile/internal/base/flag.go
src/cmd/compile/internal/gc/dep_test.go
src/cmd/compile/internal/gc/go.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/noder.go
src/cmd/compile/internal/importer/exportdata.go [new file with mode: 0644]
src/cmd/compile/internal/importer/gcimporter.go [new file with mode: 0644]
src/cmd/compile/internal/importer/gcimporter_test.go [new file with mode: 0644]
src/cmd/compile/internal/importer/iimport.go [new file with mode: 0644]
src/cmd/compile/internal/importer/support.go [new file with mode: 0644]
src/cmd/compile/internal/importer/testdata/a.go [new file with mode: 0644]
src/cmd/compile/internal/importer/testdata/b.go [new file with mode: 0644]
src/cmd/compile/internal/importer/testdata/exports.go [new file with mode: 0644]
src/cmd/compile/internal/importer/testdata/issue15920.go [new file with mode: 0644]
src/cmd/compile/internal/importer/testdata/issue20046.go [new file with mode: 0644]
src/cmd/compile/internal/importer/testdata/issue25301.go [new file with mode: 0644]
src/cmd/compile/internal/importer/testdata/issue25596.go [new file with mode: 0644]
src/cmd/compile/internal/importer/testdata/p.go [new file with mode: 0644]
src/cmd/compile/internal/importer/testdata/versions/test.go [new file with mode: 0644]
src/cmd/compile/internal/syntax/error_test.go
src/cmd/compile/internal/syntax/nodes.go
src/cmd/compile/internal/syntax/parser.go
src/cmd/compile/internal/syntax/parser_test.go
src/cmd/compile/internal/syntax/pos.go
src/cmd/compile/internal/syntax/printer.go
src/cmd/compile/internal/syntax/printer_test.go
src/cmd/compile/internal/syntax/syntax.go
src/cmd/compile/internal/syntax/testdata/go2/chans.go2 [new file with mode: 0644]
src/cmd/compile/internal/syntax/testdata/go2/linalg.go2 [new file with mode: 0644]
src/cmd/compile/internal/syntax/testdata/go2/map.go2 [new file with mode: 0644]
src/cmd/compile/internal/syntax/testdata/go2/map2.go2 [new file with mode: 0644]
src/cmd/compile/internal/syntax/testdata/go2/slices.go2 [new file with mode: 0644]
src/cmd/compile/internal/syntax/testdata/go2/smoketest.go2 [new file with mode: 0644]
src/cmd/compile/internal/syntax/testdata/go2/typeinst.go2 [new file with mode: 0644]
src/cmd/compile/internal/syntax/testdata/go2/typeinst2.go2 [new file with mode: 0644]
src/cmd/compile/internal/syntax/testdata/go2/typeparams.go2 [new file with mode: 0644]
src/cmd/compile/internal/syntax/testdata/tparams.go2 [new file with mode: 0644]
src/cmd/compile/internal/syntax/testing.go [new file with mode: 0644]
src/cmd/compile/internal/syntax/testing_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/api.go [new file with mode: 0644]
src/cmd/compile/internal/types2/api_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/assignments.go [new file with mode: 0644]
src/cmd/compile/internal/types2/builtins.go [new file with mode: 0644]
src/cmd/compile/internal/types2/builtins_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/call.go [new file with mode: 0644]
src/cmd/compile/internal/types2/check.go [new file with mode: 0644]
src/cmd/compile/internal/types2/check_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/conversions.go [new file with mode: 0644]
src/cmd/compile/internal/types2/decl.go [new file with mode: 0644]
src/cmd/compile/internal/types2/errors.go [new file with mode: 0644]
src/cmd/compile/internal/types2/errors_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/example_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/examples/functions.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/examples/methods.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/examples/types.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/expr.go [new file with mode: 0644]
src/cmd/compile/internal/types2/exprstring.go [new file with mode: 0644]
src/cmd/compile/internal/types2/exprstring_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue20583.src [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39634.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39664.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39680.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39693.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39699.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39711.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39723.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39725.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39754.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39755.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39768.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39938.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39948.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39976.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue39982.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue40038.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue40056.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue40057.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue40301.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue40684.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue41124.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue42695.src [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue42758.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue43110.src [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue43124.src [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue43125.src [new file with mode: 0644]
src/cmd/compile/internal/types2/fixedbugs/issue43190.src [new file with mode: 0644]
src/cmd/compile/internal/types2/gccgosizes.go [new file with mode: 0644]
src/cmd/compile/internal/types2/hilbert_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/importer_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/infer.go [new file with mode: 0644]
src/cmd/compile/internal/types2/initorder.go [new file with mode: 0644]
src/cmd/compile/internal/types2/issues_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/labels.go [new file with mode: 0644]
src/cmd/compile/internal/types2/lookup.go [new file with mode: 0644]
src/cmd/compile/internal/types2/methodset.go [new file with mode: 0644]
src/cmd/compile/internal/types2/object.go [new file with mode: 0644]
src/cmd/compile/internal/types2/object_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/objset.go [new file with mode: 0644]
src/cmd/compile/internal/types2/operand.go [new file with mode: 0644]
src/cmd/compile/internal/types2/package.go [new file with mode: 0644]
src/cmd/compile/internal/types2/pos.go [new file with mode: 0644]
src/cmd/compile/internal/types2/predicates.go [new file with mode: 0644]
src/cmd/compile/internal/types2/resolver.go [new file with mode: 0644]
src/cmd/compile/internal/types2/resolver_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/return.go [new file with mode: 0644]
src/cmd/compile/internal/types2/sanitize.go [new file with mode: 0644]
src/cmd/compile/internal/types2/scope.go [new file with mode: 0644]
src/cmd/compile/internal/types2/selection.go [new file with mode: 0644]
src/cmd/compile/internal/types2/self_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/sizes.go [new file with mode: 0644]
src/cmd/compile/internal/types2/sizes_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/stdlib_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/stmt.go [new file with mode: 0644]
src/cmd/compile/internal/types2/subst.go [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/blank.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/builtins.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/builtins.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/chans.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/const0.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/const1.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/constdecl.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/conversions.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/conversions2.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/cycles.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/cycles1.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/cycles2.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/cycles3.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/cycles4.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/cycles5.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/decls0.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/decls1.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/decls2/decls2a.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/decls2/decls2b.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/decls3.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/decls4.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/decls5.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/errors.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/expr0.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/expr1.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/expr2.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/expr3.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/gotos.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/importC.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/importdecl0/importdecl0a.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/importdecl0/importdecl0b.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/importdecl1/importdecl1a.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/importdecl1/importdecl1b.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/init0.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/init1.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/init2.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/issue23203a.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/issue23203b.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/issue25008/issue25008a.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/issue25008/issue25008b.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/issue26390.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/issue28251.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/issue6977.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/issues.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/issues.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/labels.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/linalg.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/literals.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/main.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/main.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/map.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/map2.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/methodsets.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/mtypeparams.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/shifts.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/slices.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/stmt0.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/stmt1.src [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/tinference.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/tmp.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/typeinst.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/typeinst2.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/typeparams.go2 [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/vardecl.src [new file with mode: 0644]
src/cmd/compile/internal/types2/type.go [new file with mode: 0644]
src/cmd/compile/internal/types2/typestring.go [new file with mode: 0644]
src/cmd/compile/internal/types2/typestring_test.go [new file with mode: 0644]
src/cmd/compile/internal/types2/typexpr.go [new file with mode: 0644]
src/cmd/compile/internal/types2/unify.go [new file with mode: 0644]
src/cmd/compile/internal/types2/universe.go [new file with mode: 0644]
src/cmd/compile/internal/types2/walk.go [new file with mode: 0644]
src/cmd/dist/buildtool.go
src/go/ast/ast.go
src/go/ast/example_test.go
src/go/ast/walk.go
src/go/internal/gccgoimporter/importer_test.go
src/go/parser/error_test.go
src/go/parser/interface.go
src/go/parser/parser.go
src/go/parser/short_test.go
src/go/parser/testdata/chans.go2 [new file with mode: 0644]
src/go/parser/testdata/linalg.go2 [new file with mode: 0644]
src/go/parser/testdata/map.go2 [new file with mode: 0644]
src/go/parser/testdata/metrics.go2 [new file with mode: 0644]
src/go/parser/testdata/set.go2 [new file with mode: 0644]
src/go/parser/testdata/slices.go2 [new file with mode: 0644]
src/go/parser/testdata/sort.go2 [new file with mode: 0644]
src/go/printer/nodes.go
src/go/printer/printer_test.go
src/go/printer/testdata/declarations.golden
src/go/printer/testdata/declarations.input
src/go/printer/testdata/generics.golden [new file with mode: 0644]
src/go/printer/testdata/generics.input [new file with mode: 0644]
src/go/types/api.go
src/go/types/check.go
src/go/types/decl.go
src/go/types/expr.go
src/go/types/exprstring.go
src/go/types/infer.go [new file with mode: 0644]
src/go/types/lookup.go
src/go/types/methodset.go
src/go/types/object.go
src/go/types/predicates.go
src/go/types/resolver.go
src/go/types/sanitize.go [new file with mode: 0644]
src/go/types/scope.go
src/go/types/sizes.go
src/go/types/stmt.go
src/go/types/subst.go [new file with mode: 0644]
src/go/types/testdata/decls0.src
src/go/types/testdata/issues.src
src/go/types/type.go
src/go/types/typestring.go
src/go/types/typestring_test.go
src/go/types/typexpr.go
src/go/types/unify.go [new file with mode: 0644]
src/go/types/universe.go
test/alias2.go
test/append1.go
test/assign.go
test/blank1.go
test/cannotassign.go
test/chan/perm.go
test/cmp6.go
test/const1.go
test/const2.go
test/convert2.go
test/convlit.go
test/copy1.go
test/fixedbugs/bug040.go
test/fixedbugs/bug062.go
test/fixedbugs/bug081.go
test/fixedbugs/bug090.go
test/fixedbugs/bug122.go
test/fixedbugs/bug131.go
test/fixedbugs/bug132.go
test/fixedbugs/bug163.go
test/fixedbugs/bug175.go
test/fixedbugs/bug192.go
test/fixedbugs/bug205.go
test/fixedbugs/bug215.go
test/fixedbugs/bug223.go
test/fixedbugs/bug224.go
test/fixedbugs/bug229.go
test/fixedbugs/bug280.go
test/fixedbugs/bug289.go
test/fixedbugs/bug325.go
test/fixedbugs/bug326.go
test/fixedbugs/bug340.go
test/fixedbugs/bug342.go
test/fixedbugs/bug350.go
test/fixedbugs/bug357.go
test/fixedbugs/bug362.go
test/fixedbugs/bug371.go
test/fixedbugs/bug379.go
test/fixedbugs/bug383.go
test/fixedbugs/bug386.go
test/fixedbugs/bug389.go
test/fixedbugs/bug390.go
test/fixedbugs/bug397.go
test/fixedbugs/bug416.go
test/fixedbugs/bug418.go
test/fixedbugs/bug462.go
test/fixedbugs/bug463.go
test/fixedbugs/bug487.go
test/fixedbugs/issue10975.go
test/fixedbugs/issue11326.go
test/fixedbugs/issue11361.go
test/fixedbugs/issue11371.go
test/fixedbugs/issue11674.go
test/fixedbugs/issue11737.go
test/fixedbugs/issue13365.go
test/fixedbugs/issue13471.go
test/fixedbugs/issue13480.go
test/fixedbugs/issue13485.go
test/fixedbugs/issue13539.go
test/fixedbugs/issue13559.go
test/fixedbugs/issue14136.go
test/fixedbugs/issue14321.go
test/fixedbugs/issue14729.go
test/fixedbugs/issue15055.go
test/fixedbugs/issue15898.go
test/fixedbugs/issue16439.go
test/fixedbugs/issue16949.go
test/fixedbugs/issue17588.go
test/fixedbugs/issue18392.go
test/fixedbugs/issue19323.go
test/fixedbugs/issue19482.go
test/fixedbugs/issue19699b.go
test/fixedbugs/issue19880.go
test/fixedbugs/issue19947.go
test/fixedbugs/issue20185.go
test/fixedbugs/issue20415.go
test/fixedbugs/issue20749.go
test/fixedbugs/issue22389.go
test/fixedbugs/issue22794.go
test/fixedbugs/issue22822.go
test/fixedbugs/issue23094.go
test/fixedbugs/issue23609.go
test/fixedbugs/issue23823.go
test/fixedbugs/issue24470.go
test/fixedbugs/issue25727.go
test/fixedbugs/issue26616.go
test/fixedbugs/issue27595.go
test/fixedbugs/issue28079c.go
test/fixedbugs/issue28450.go
test/fixedbugs/issue30085.go
test/fixedbugs/issue30087.go
test/fixedbugs/issue35291.go
test/fixedbugs/issue38117.go
test/fixedbugs/issue38745.go
test/fixedbugs/issue3925.go
test/fixedbugs/issue4085a.go
test/fixedbugs/issue41500.go
test/fixedbugs/issue4215.go
test/fixedbugs/issue4251.go
test/fixedbugs/issue4429.go
test/fixedbugs/issue4458.go
test/fixedbugs/issue4470.go
test/fixedbugs/issue4517d.go
test/fixedbugs/issue4909a.go
test/fixedbugs/issue6402.go
test/fixedbugs/issue6572.go
test/fixedbugs/issue6750.go
test/fixedbugs/issue6772.go
test/fixedbugs/issue7129.go
test/fixedbugs/issue7150.go
test/fixedbugs/issue7153.go
test/fixedbugs/issue7223.go
test/fixedbugs/issue7310.go
test/fixedbugs/issue8183.go
test/fixedbugs/issue8438.go
test/fixedbugs/issue8440.go
test/fixedbugs/issue8745.go
test/fixedbugs/issue9083.go
test/fixedbugs/issue9370.go
test/fixedbugs/issue9432.go
test/fixedbugs/issue9634.go
test/func1.go
test/funcdup.go
test/funcdup2.go
test/init.go
test/initloop.go
test/interface/embed2.go
test/interface/explicit.go
test/interface/pointer.go
test/interface/receiver1.go
test/makechan.go
test/makemap.go
test/makenew.go
test/map1.go
test/method2.go
test/method6.go
test/named1.go
test/rename1.go
test/run.go
test/runtime.go
test/slice3err.go
test/switch3.go
test/switch5.go
test/switch6.go
test/switch7.go
test/typecheckloop.go
test/typeparam/importtest.go [new file with mode: 0644]
test/typeparam/smoketest.go [new file with mode: 0644]
test/typeparam/tparam1.go [new file with mode: 0644]
test/typeswitch3.go
test/used.go
test/varerr.go

index a23b0a00d1a1c9b0cf481a179a307766efe9a2a0..d21d2ff61f18ff19e1ac353ac83a39acba08cf44 100644 (file)
@@ -1,2 +1,2 @@
-branch: dev.regabi
-parent-branch: master
+branch: dev.typeparams
+parent-branch: dev.regabi
index 9bc059c2e44f9bd72eaf20ac2a6b09ff84a82299..9105bac1912455530cd1651d51994420200f9019 100644 (file)
@@ -20,56 +20,83 @@ package main_test
 // An absent entry means that the format is not recognized as valid.
 // An empty new format means that the format should remain unchanged.
 var knownFormats = map[string]string{
-       "*bytes.Buffer %s":                             "",
-       "*cmd/compile/internal/ssa.Block %s":           "",
-       "*cmd/compile/internal/ssa.Func %s":            "",
-       "*cmd/compile/internal/ssa.Register %s":        "",
-       "*cmd/compile/internal/ssa.Value %s":           "",
-       "*cmd/compile/internal/types.Sym %+v":          "",
-       "*cmd/compile/internal/types.Sym %S":           "",
-       "*cmd/compile/internal/types.Type %+v":         "",
-       "*cmd/compile/internal/types.Type %-S":         "",
-       "*cmd/compile/internal/types.Type %L":          "",
-       "*cmd/compile/internal/types.Type %S":          "",
-       "*cmd/compile/internal/types.Type %s":          "",
-       "*math/big.Float %f":                           "",
-       "*math/big.Int %s":                             "",
-       "[]cmd/compile/internal/syntax.token %s":       "",
-       "cmd/compile/internal/arm.shift %d":            "",
-       "cmd/compile/internal/gc.RegIndex %d":          "",
-       "cmd/compile/internal/gc.initKind %d":          "",
-       "cmd/compile/internal/ir.Class %d":             "",
-       "cmd/compile/internal/ir.Node %+v":             "",
-       "cmd/compile/internal/ir.Node %L":              "",
-       "cmd/compile/internal/ir.Nodes %+v":            "",
-       "cmd/compile/internal/ir.Nodes %.v":            "",
-       "cmd/compile/internal/ir.Op %+v":               "",
-       "cmd/compile/internal/ssa.Aux %#v":             "",
-       "cmd/compile/internal/ssa.Aux %q":              "",
-       "cmd/compile/internal/ssa.Aux %s":              "",
-       "cmd/compile/internal/ssa.BranchPrediction %d": "",
-       "cmd/compile/internal/ssa.ID %d":               "",
-       "cmd/compile/internal/ssa.LocalSlot %s":        "",
-       "cmd/compile/internal/ssa.Location %s":         "",
-       "cmd/compile/internal/ssa.Op %s":               "",
-       "cmd/compile/internal/ssa.ValAndOff %s":        "",
-       "cmd/compile/internal/ssa.flagConstant %s":     "",
-       "cmd/compile/internal/ssa.rbrank %d":           "",
-       "cmd/compile/internal/ssa.regMask %d":          "",
-       "cmd/compile/internal/ssa.register %d":         "",
-       "cmd/compile/internal/ssa.relation %s":         "",
-       "cmd/compile/internal/syntax.Error %q":         "",
-       "cmd/compile/internal/syntax.Expr %#v":         "",
-       "cmd/compile/internal/syntax.LitKind %d":       "",
-       "cmd/compile/internal/syntax.Operator %s":      "",
-       "cmd/compile/internal/syntax.Pos %s":           "",
-       "cmd/compile/internal/syntax.position %s":      "",
-       "cmd/compile/internal/syntax.token %q":         "",
-       "cmd/compile/internal/syntax.token %s":         "",
-       "cmd/compile/internal/types.Kind %d":           "",
-       "cmd/compile/internal/types.Kind %s":           "",
-       "go/constant.Value %#v":                        "",
-       "math/big.Accuracy %s":                         "",
-       "reflect.Type %s":                              "",
-       "time.Duration %d":                             "",
+       "*bytes.Buffer %s":                                                               "",
+       "*cmd/compile/internal/ssa.Block %s":                                             "",
+       "*cmd/compile/internal/ssa.Func %s":                                              "",
+       "*cmd/compile/internal/ssa.Register %s":                                          "",
+       "*cmd/compile/internal/ssa.Value %s":                                             "",
+       "*cmd/compile/internal/syntax.CallExpr %s":                                       "",
+       "*cmd/compile/internal/syntax.FuncLit %s":                                        "",
+       "*cmd/compile/internal/syntax.IndexExpr %s":                                      "",
+       "*cmd/compile/internal/types.Sym %+v":                                            "",
+       "*cmd/compile/internal/types.Sym %S":                                             "",
+       "*cmd/compile/internal/types.Type %+v":                                           "",
+       "*cmd/compile/internal/types.Type %-S":                                           "",
+       "*cmd/compile/internal/types.Type %L":                                            "",
+       "*cmd/compile/internal/types.Type %S":                                            "",
+       "*cmd/compile/internal/types.Type %s":                                            "",
+       "*cmd/compile/internal/types2.Basic %s":                                          "",
+       "*cmd/compile/internal/types2.Chan %s":                                           "",
+       "*cmd/compile/internal/types2.Func %s":                                           "",
+       "*cmd/compile/internal/types2.Initializer %s":                                    "",
+       "*cmd/compile/internal/types2.Interface %s":                                      "",
+       "*cmd/compile/internal/types2.MethodSet %s":                                      "",
+       "*cmd/compile/internal/types2.Named %s":                                          "",
+       "*cmd/compile/internal/types2.Package %s":                                        "",
+       "*cmd/compile/internal/types2.Selection %s":                                      "",
+       "*cmd/compile/internal/types2.Signature %s":                                      "",
+       "*cmd/compile/internal/types2.TypeName %s":                                       "",
+       "*cmd/compile/internal/types2.TypeParam %s":                                      "",
+       "*cmd/compile/internal/types2.Var %s":                                            "",
+       "*cmd/compile/internal/types2.operand %s":                                        "",
+       "*cmd/compile/internal/types2.substMap %s":                                       "",
+       "*math/big.Float %f":                                                             "",
+       "*math/big.Int %s":                                                               "",
+       "[]*cmd/compile/internal/types2.TypeName %s":                                     "",
+       "[]cmd/compile/internal/syntax.token %s":                                         "",
+       "[]cmd/compile/internal/types2.Type %s":                                          "",
+       "cmd/compile/internal/arm.shift %d":                                              "",
+       "cmd/compile/internal/gc.RegIndex %d":                                            "",
+       "cmd/compile/internal/gc.initKind %d":                                            "",
+       "cmd/compile/internal/ir.Class %d":                                               "",
+       "cmd/compile/internal/ir.Node %+v":                                               "",
+       "cmd/compile/internal/ir.Node %L":                                                "",
+       "cmd/compile/internal/ir.Nodes %+v":                                              "",
+       "cmd/compile/internal/ir.Nodes %.v":                                              "",
+       "cmd/compile/internal/ir.Op %+v":                                                 "",
+       "cmd/compile/internal/ssa.Aux %#v":                                               "",
+       "cmd/compile/internal/ssa.Aux %q":                                                "",
+       "cmd/compile/internal/ssa.Aux %s":                                                "",
+       "cmd/compile/internal/ssa.BranchPrediction %d":                                   "",
+       "cmd/compile/internal/ssa.ID %d":                                                 "",
+       "cmd/compile/internal/ssa.LocalSlot %s":                                          "",
+       "cmd/compile/internal/ssa.Location %s":                                           "",
+       "cmd/compile/internal/ssa.Op %s":                                                 "",
+       "cmd/compile/internal/ssa.ValAndOff %s":                                          "",
+       "cmd/compile/internal/ssa.flagConstant %s":                                       "",
+       "cmd/compile/internal/ssa.rbrank %d":                                             "",
+       "cmd/compile/internal/ssa.regMask %d":                                            "",
+       "cmd/compile/internal/ssa.register %d":                                           "",
+       "cmd/compile/internal/ssa.relation %s":                                           "",
+       "cmd/compile/internal/syntax.ChanDir %d":                                         "",
+       "cmd/compile/internal/syntax.Error %q":                                           "",
+       "cmd/compile/internal/syntax.Expr %#v":                                           "",
+       "cmd/compile/internal/syntax.Expr %s":                                            "",
+       "cmd/compile/internal/syntax.LitKind %d":                                         "",
+       "cmd/compile/internal/syntax.Operator %s":                                        "",
+       "cmd/compile/internal/syntax.Pos %s":                                             "",
+       "cmd/compile/internal/syntax.position %s":                                        "",
+       "cmd/compile/internal/syntax.token %q":                                           "",
+       "cmd/compile/internal/syntax.token %s":                                           "",
+       "cmd/compile/internal/types.Kind %d":                                             "",
+       "cmd/compile/internal/types.Kind %s":                                             "",
+       "cmd/compile/internal/types2.Object %s":                                          "",
+       "cmd/compile/internal/types2.Type %s":                                            "",
+       "cmd/compile/internal/types2.color %s":                                           "",
+       "go/constant.Value %#v":                                                          "",
+       "go/constant.Value %s":                                                           "",
+       "map[*cmd/compile/internal/types2.TypeParam]cmd/compile/internal/types2.Type %s": "",
+       "math/big.Accuracy %s":                                                           "",
+       "reflect.Type %s":                                                                "",
+       "time.Duration %d":                                                               "",
 }
index ce87ff730eaa7c19ee5101012be71d0809dd97ec..898cb5470b7fbb6872f513e2ede5e63593d54618 100644 (file)
@@ -54,6 +54,7 @@ type CmdFlags struct {
        C CountFlag    "help:\"disable printing of columns in error messages\""
        D string       "help:\"set relative `path` for local imports\""
        E CountFlag    "help:\"debug symbol export\""
+       G CountFlag    "help:\"accept generic code\""
        I func(string) "help:\"add `directory` to import search path\""
        K CountFlag    "help:\"debug missing line numbers\""
        L CountFlag    "help:\"show full file names in error messages\""
index a185bc9f547c5261b4c81b0abad34aea62570819..d03683a2808c39b2084c39fd35e087082a2414f3 100644 (file)
@@ -19,7 +19,12 @@ func TestDeps(t *testing.T) {
        for _, dep := range strings.Fields(strings.Trim(string(out), "[]")) {
                switch dep {
                case "go/build", "go/scanner":
-                       t.Errorf("undesired dependency on %q", dep)
+                       // cmd/compile/internal/importer introduces a dependency
+                       // on go/build and go/token; cmd/compile/internal/ uses
+                       // go/constant which uses go/token in its API. Once we
+                       // got rid of those dependencies, enable this check again.
+                       // TODO(gri) fix this
+                       // t.Errorf("undesired dependency on %q", dep)
                }
        }
 }
index df91f6f530aa43114e1b63c8c733d579805af7df..9e8719dc0bb2fdfb9383c52008878cf714b395ee 100644 (file)
@@ -80,6 +80,8 @@ var pragcgobuf [][]string
 
 var decldepth int32
 
+var nolocalimports bool
+
 var inimport bool // set during import
 
 var itabpkg *types.Pkg // fake pkg for itab entries
index 94b4e0e674e82f8ae6a6b577d19c18eb667227a9..b9454604f0d5814289d7d15f6a11a28d76dfc517 100644 (file)
@@ -218,6 +218,12 @@ func Main(archInit func(*Arch)) {
        cgoSymABIs()
        timings.Stop()
        timings.AddEvent(int64(lines), "lines")
+       if base.Flag.G != 0 && base.Flag.G < 3 {
+               // can only parse generic code for now
+               base.ExitIfErrors()
+               return
+       }
+
        recordPackageName()
 
        // Typecheck.
index 97a9ac4396194ac51348f32378c95f9538a73f83..8beef0d18b0f22f25aa3c500485c8e244ed67fdd 100644 (file)
@@ -8,6 +8,7 @@ import (
        "fmt"
        "go/constant"
        "go/token"
+       "io"
        "os"
        "path/filepath"
        "runtime"
@@ -17,9 +18,11 @@ import (
        "unicode/utf8"
 
        "cmd/compile/internal/base"
+       "cmd/compile/internal/importer"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/syntax"
        "cmd/compile/internal/types"
+       "cmd/compile/internal/types2"
        "cmd/internal/objabi"
        "cmd/internal/src"
 )
@@ -28,7 +31,7 @@ import (
 // Each declaration in every *syntax.File is converted to a syntax tree
 // and its root represented by *Node is appended to Target.Decls.
 // Returns the total count of parsed lines.
-func parseFiles(filenames []string) uint {
+func parseFiles(filenames []string) (lines uint) {
        noders := make([]*noder, 0, len(filenames))
        // Limit the number of simultaneously open files.
        sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10)
@@ -45,7 +48,7 @@ func parseFiles(filenames []string) uint {
                        sem <- struct{}{}
                        defer func() { <-sem }()
                        defer close(p.err)
-                       base := syntax.NewFileBase(filename)
+                       fbase := syntax.NewFileBase(filename)
 
                        f, err := os.Open(filename)
                        if err != nil {
@@ -54,23 +57,106 @@ func parseFiles(filenames []string) uint {
                        }
                        defer f.Close()
 
-                       p.file, _ = syntax.Parse(base, f, p.error, p.pragma, syntax.CheckBranches) // errors are tracked via p.error
+                       mode := syntax.CheckBranches
+                       if base.Flag.G != 0 {
+                               mode |= syntax.AllowGenerics
+                       }
+                       p.file, _ = syntax.Parse(fbase, f, p.error, p.pragma, mode) // errors are tracked via p.error
                }(filename)
        }
 
-       var lines uint
+       // generic noding phase (using new typechecker)
+       if base.Flag.G != 0 {
+               // setup and syntax error reporting
+               nodersmap := make(map[string]*noder)
+               var files []*syntax.File
+               for _, p := range noders {
+                       for e := range p.err {
+                               p.errorAt(e.Pos, "%s", e.Msg)
+                       }
+
+                       nodersmap[p.file.Pos().RelFilename()] = p
+                       files = append(files, p.file)
+                       lines += p.file.EOF.Line()
+
+               }
+               if base.SyntaxErrors() != 0 {
+                       base.ErrorExit()
+               }
+
+               // typechecking
+               conf := types2.Config{
+                       InferFromConstraints:  true,
+                       IgnoreBranches:        true, // parser already checked via syntax.CheckBranches mode
+                       CompilerErrorMessages: true, // use error strings matching existing compiler errors
+                       Error: func(err error) {
+                               terr := err.(types2.Error)
+                               if len(terr.Msg) > 0 && terr.Msg[0] == '\t' {
+                                       // types2 reports error clarifications via separate
+                                       // error messages which are indented with a tab.
+                                       // Ignore them to satisfy tools and tests that expect
+                                       // only one error in such cases.
+                                       // TODO(gri) Need to adjust error reporting in types2.
+                                       return
+                               }
+                               p := nodersmap[terr.Pos.RelFilename()]
+                               base.ErrorfAt(p.makeXPos(terr.Pos), "%s", terr.Msg)
+                       },
+                       Importer: &gcimports{
+                               packages: make(map[string]*types2.Package),
+                               lookup: func(path string) (io.ReadCloser, error) {
+                                       file, ok := findpkg(path)
+                                       if !ok {
+                                               return nil, fmt.Errorf("can't find import: %q", path)
+                                       }
+                                       return os.Open(file)
+                               },
+                       },
+               }
+               info := types2.Info{
+                       Types:      make(map[syntax.Expr]types2.TypeAndValue),
+                       Defs:       make(map[*syntax.Name]types2.Object),
+                       Uses:       make(map[*syntax.Name]types2.Object),
+                       Selections: make(map[*syntax.SelectorExpr]*types2.Selection),
+                       // expand as needed
+               }
+               conf.Check(base.Ctxt.Pkgpath, files, &info)
+               base.ExitIfErrors()
+               if base.Flag.G < 2 {
+                       return
+               }
+
+               // noding
+               for _, p := range noders {
+                       // errors have already been reported
+
+                       p.typeInfo = &info
+                       p.node()
+                       lines += p.file.EOF.Line()
+                       p.file = nil // release memory
+                       base.ExitIfErrors()
+
+                       // Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
+                       testdclstack()
+               }
+
+               types.LocalPkg.Height = myheight
+               return
+       }
+
+       // traditional (non-generic) noding phase
        for _, p := range noders {
                for e := range p.err {
                        p.errorAt(e.Pos, "%s", e.Msg)
                }
 
                p.node()
-               lines += p.file.Lines
+               lines += p.file.EOF.Line()
                p.file = nil // release memory
-
                if base.SyntaxErrors() != 0 {
                        base.ErrorExit()
                }
+
                // Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
                testdclstack()
        }
@@ -80,8 +166,24 @@ func parseFiles(filenames []string) uint {
        }
 
        types.LocalPkg.Height = myheight
+       return
+}
 
-       return lines
+// Temporary import helper to get type2-based type-checking going.
+type gcimports struct {
+       packages map[string]*types2.Package
+       lookup   func(path string) (io.ReadCloser, error)
+}
+
+func (m *gcimports) Import(path string) (*types2.Package, error) {
+       return m.ImportFrom(path, "" /* no vendoring */, 0)
+}
+
+func (m *gcimports) ImportFrom(path, srcDir string, mode types2.ImportMode) (*types2.Package, error) {
+       if mode != 0 {
+               panic("mode must be 0")
+       }
+       return importer.Import(m.packages, path, srcDir, m.lookup)
 }
 
 // makeSrcPosBase translates from a *syntax.PosBase to a *src.PosBase.
@@ -154,9 +256,40 @@ type noder struct {
        trackScopes bool
        scopeVars   []int
 
+       // typeInfo provides access to the type information computed by the new
+       // typechecker. It is only present if -G is set, and all noders point to
+       // the same types.Info. For now this is a local field, if need be we can
+       // make it global.
+       typeInfo *types2.Info
+
        lastCloseScopePos syntax.Pos
 }
 
+// For now we provide these basic accessors to get to type and object
+// information of expression nodes during noding. Eventually we will
+// attach this information directly to the syntax tree which should
+// simplify access and make it more efficient as well.
+
+// typ returns the type and value information for the given expression.
+func (p *noder) typ(x syntax.Expr) types2.TypeAndValue {
+       return p.typeInfo.Types[x]
+}
+
+// def returns the object for the given name in its declaration.
+func (p *noder) def(x *syntax.Name) types2.Object {
+       return p.typeInfo.Defs[x]
+}
+
+// use returns the object for the given name outside its declaration.
+func (p *noder) use(x *syntax.Name) types2.Object {
+       return p.typeInfo.Uses[x]
+}
+
+// sel returns the selection information for the given selector expression.
+func (p *noder) sel(x *syntax.SelectorExpr) *types2.Selection {
+       return p.typeInfo.Selections[x]
+}
+
 func (p *noder) funcBody(fn *ir.Func, block *syntax.BlockStmt) {
        oldScope := p.scope
        p.scope = 0
@@ -318,7 +451,7 @@ func (p *noder) decls(decls []syntax.Decl) (l []ir.Node) {
 }
 
 func (p *noder) importDecl(imp *syntax.ImportDecl) {
-       if imp.Path.Bad {
+       if imp.Path == nil || imp.Path.Bad {
                return // avoid follow-on errors if there was a syntax error
        }
 
diff --git a/src/cmd/compile/internal/importer/exportdata.go b/src/cmd/compile/internal/importer/exportdata.go
new file mode 100644 (file)
index 0000000..3925a64
--- /dev/null
@@ -0,0 +1,92 @@
+// UNREVIEWED
+// Copyright 2011 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.
+
+// This file implements FindExportData.
+
+package importer
+
+import (
+       "bufio"
+       "fmt"
+       "io"
+       "strconv"
+       "strings"
+)
+
+func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
+       // See $GOROOT/include/ar.h.
+       hdr := make([]byte, 16+12+6+6+8+10+2)
+       _, err = io.ReadFull(r, hdr)
+       if err != nil {
+               return
+       }
+       // leave for debugging
+       if false {
+               fmt.Printf("header: %s", hdr)
+       }
+       s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
+       size, err = strconv.Atoi(s)
+       if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
+               err = fmt.Errorf("invalid archive header")
+               return
+       }
+       name = strings.TrimSpace(string(hdr[:16]))
+       return
+}
+
+// FindExportData positions the reader r at the beginning of the
+// export data section of an underlying GC-created object/archive
+// file by reading from it. The reader must be positioned at the
+// start of the file before calling this function. The hdr result
+// is the string before the export data, either "$$" or "$$B".
+//
+func FindExportData(r *bufio.Reader) (hdr string, err error) {
+       // Read first line to make sure this is an object file.
+       line, err := r.ReadSlice('\n')
+       if err != nil {
+               err = fmt.Errorf("can't find export data (%v)", err)
+               return
+       }
+
+       if string(line) == "!<arch>\n" {
+               // Archive file. Scan to __.PKGDEF.
+               var name string
+               if name, _, err = readGopackHeader(r); err != nil {
+                       return
+               }
+
+               // First entry should be __.PKGDEF.
+               if name != "__.PKGDEF" {
+                       err = fmt.Errorf("go archive is missing __.PKGDEF")
+                       return
+               }
+
+               // Read first line of __.PKGDEF data, so that line
+               // is once again the first line of the input.
+               if line, err = r.ReadSlice('\n'); err != nil {
+                       err = fmt.Errorf("can't find export data (%v)", err)
+                       return
+               }
+       }
+
+       // Now at __.PKGDEF in archive or still at beginning of file.
+       // Either way, line should begin with "go object ".
+       if !strings.HasPrefix(string(line), "go object ") {
+               err = fmt.Errorf("not a Go object file")
+               return
+       }
+
+       // Skip over object header to export data.
+       // Begins after first line starting with $$.
+       for line[0] != '$' {
+               if line, err = r.ReadSlice('\n'); err != nil {
+                       err = fmt.Errorf("can't find export data (%v)", err)
+                       return
+               }
+       }
+       hdr = string(line)
+
+       return
+}
diff --git a/src/cmd/compile/internal/importer/gcimporter.go b/src/cmd/compile/internal/importer/gcimporter.go
new file mode 100644 (file)
index 0000000..feb18cf
--- /dev/null
@@ -0,0 +1,175 @@
+// UNREVIEWED
+// Copyright 2011 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 importer implements Import for gc-generated object files.
+package importer
+
+import (
+       "bufio"
+       "cmd/compile/internal/types2"
+       "fmt"
+       "go/build"
+       "io"
+       "io/ioutil"
+       "os"
+       "path/filepath"
+       "strings"
+)
+
+// debugging/development support
+const debug = false
+
+var pkgExts = [...]string{".a", ".o"}
+
+// FindPkg returns the filename and unique package id for an import
+// path based on package information provided by build.Import (using
+// the build.Default build.Context). A relative srcDir is interpreted
+// relative to the current working directory.
+// If no file was found, an empty filename is returned.
+//
+func FindPkg(path, srcDir string) (filename, id string) {
+       if path == "" {
+               return
+       }
+
+       var noext string
+       switch {
+       default:
+               // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
+               // Don't require the source files to be present.
+               if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282
+                       srcDir = abs
+               }
+               bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
+               if bp.PkgObj == "" {
+                       id = path // make sure we have an id to print in error message
+                       return
+               }
+               noext = strings.TrimSuffix(bp.PkgObj, ".a")
+               id = bp.ImportPath
+
+       case build.IsLocalImport(path):
+               // "./x" -> "/this/directory/x.ext", "/this/directory/x"
+               noext = filepath.Join(srcDir, path)
+               id = noext
+
+       case filepath.IsAbs(path):
+               // for completeness only - go/build.Import
+               // does not support absolute imports
+               // "/x" -> "/x.ext", "/x"
+               noext = path
+               id = path
+       }
+
+       if false { // for debugging
+               if path != id {
+                       fmt.Printf("%s -> %s\n", path, id)
+               }
+       }
+
+       // try extensions
+       for _, ext := range pkgExts {
+               filename = noext + ext
+               if f, err := os.Stat(filename); err == nil && !f.IsDir() {
+                       return
+               }
+       }
+
+       filename = "" // not found
+       return
+}
+
+// Import imports a gc-generated package given its import path and srcDir, adds
+// the corresponding package object to the packages map, and returns the object.
+// The packages map must contain all packages already imported.
+//
+func Import(packages map[string]*types2.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types2.Package, err error) {
+       var rc io.ReadCloser
+       var id string
+       if lookup != nil {
+               // With custom lookup specified, assume that caller has
+               // converted path to a canonical import path for use in the map.
+               if path == "unsafe" {
+                       return types2.Unsafe, nil
+               }
+               id = path
+
+               // No need to re-import if the package was imported completely before.
+               if pkg = packages[id]; pkg != nil && pkg.Complete() {
+                       return
+               }
+               f, err := lookup(path)
+               if err != nil {
+                       return nil, err
+               }
+               rc = f
+       } else {
+               var filename string
+               filename, id = FindPkg(path, srcDir)
+               if filename == "" {
+                       if path == "unsafe" {
+                               return types2.Unsafe, nil
+                       }
+                       return nil, fmt.Errorf("can't find import: %q", id)
+               }
+
+               // no need to re-import if the package was imported completely before
+               if pkg = packages[id]; pkg != nil && pkg.Complete() {
+                       return
+               }
+
+               // open file
+               f, err := os.Open(filename)
+               if err != nil {
+                       return nil, err
+               }
+               defer func() {
+                       if err != nil {
+                               // add file name to error
+                               err = fmt.Errorf("%s: %v", filename, err)
+                       }
+               }()
+               rc = f
+       }
+       defer rc.Close()
+
+       var hdr string
+       buf := bufio.NewReader(rc)
+       if hdr, err = FindExportData(buf); err != nil {
+               return
+       }
+
+       switch hdr {
+       case "$$\n":
+               err = fmt.Errorf("import %q: old textual export format no longer supported (recompile library)", path)
+
+       case "$$B\n":
+               var data []byte
+               data, err = ioutil.ReadAll(buf)
+               if err != nil {
+                       break
+               }
+
+               // The indexed export format starts with an 'i'; the older
+               // binary export format starts with a 'c', 'd', or 'v'
+               // (from "version"). Select appropriate importer.
+               if len(data) > 0 && data[0] == 'i' {
+                       _, pkg, err = iImportData(packages, data[1:], id)
+               } else {
+                       err = fmt.Errorf("import %q: old binary export format no longer supported (recompile library)", path)
+               }
+
+       default:
+               err = fmt.Errorf("import %q: unknown export data header: %q", path, hdr)
+       }
+
+       return
+}
+
+type byPath []*types2.Package
+
+func (a byPath) Len() int           { return len(a) }
+func (a byPath) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() }
diff --git a/src/cmd/compile/internal/importer/gcimporter_test.go b/src/cmd/compile/internal/importer/gcimporter_test.go
new file mode 100644 (file)
index 0000000..a275524
--- /dev/null
@@ -0,0 +1,612 @@
+// UNREVIEWED
+// Copyright 2011 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 importer
+
+import (
+       "bytes"
+       "cmd/compile/internal/types2"
+       "fmt"
+       "internal/testenv"
+       "io/ioutil"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "runtime"
+       "strings"
+       "testing"
+       "time"
+)
+
+// skipSpecialPlatforms causes the test to be skipped for platforms where
+// builders (build.golang.org) don't have access to compiled packages for
+// import.
+func skipSpecialPlatforms(t *testing.T) {
+       switch platform := runtime.GOOS + "-" + runtime.GOARCH; platform {
+       case "darwin-arm64":
+               t.Skipf("no compiled packages available for import on %s", platform)
+       }
+}
+
+// compile runs the compiler on filename, with dirname as the working directory,
+// and writes the output file to outdirname.
+func compile(t *testing.T, dirname, filename, outdirname string) string {
+       // filename must end with ".go"
+       if !strings.HasSuffix(filename, ".go") {
+               t.Fatalf("filename doesn't end in .go: %s", filename)
+       }
+       basename := filepath.Base(filename)
+       outname := filepath.Join(outdirname, basename[:len(basename)-2]+"o")
+       cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", outname, filename)
+       cmd.Dir = dirname
+       out, err := cmd.CombinedOutput()
+       if err != nil {
+               t.Logf("%s", out)
+               t.Fatalf("go tool compile %s failed: %s", filename, err)
+       }
+       return outname
+}
+
+func testPath(t *testing.T, path, srcDir string) *types2.Package {
+       t0 := time.Now()
+       pkg, err := Import(make(map[string]*types2.Package), path, srcDir, nil)
+       if err != nil {
+               t.Errorf("testPath(%s): %s", path, err)
+               return nil
+       }
+       t.Logf("testPath(%s): %v", path, time.Since(t0))
+       return pkg
+}
+
+const maxTime = 30 * time.Second
+
+func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
+       dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
+       list, err := ioutil.ReadDir(dirname)
+       if err != nil {
+               t.Fatalf("testDir(%s): %s", dirname, err)
+       }
+       for _, f := range list {
+               if time.Now().After(endTime) {
+                       t.Log("testing time used up")
+                       return
+               }
+               switch {
+               case !f.IsDir():
+                       // try extensions
+                       for _, ext := range pkgExts {
+                               if strings.HasSuffix(f.Name(), ext) {
+                                       name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension
+                                       if testPath(t, filepath.Join(dir, name), dir) != nil {
+                                               nimports++
+                                       }
+                               }
+                       }
+               case f.IsDir():
+                       nimports += testDir(t, filepath.Join(dir, f.Name()), endTime)
+               }
+       }
+       return
+}
+
+func mktmpdir(t *testing.T) string {
+       tmpdir, err := ioutil.TempDir("", "gcimporter_test")
+       if err != nil {
+               t.Fatal("mktmpdir:", err)
+       }
+       if err := os.Mkdir(filepath.Join(tmpdir, "testdata"), 0700); err != nil {
+               os.RemoveAll(tmpdir)
+               t.Fatal("mktmpdir:", err)
+       }
+       return tmpdir
+}
+
+func TestImportTestdata(t *testing.T) {
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       tmpdir := mktmpdir(t)
+       defer os.RemoveAll(tmpdir)
+
+       compile(t, "testdata", "exports.go", filepath.Join(tmpdir, "testdata"))
+
+       if pkg := testPath(t, "./testdata/exports", tmpdir); pkg != nil {
+               // The package's Imports list must include all packages
+               // explicitly imported by exports.go, plus all packages
+               // referenced indirectly via exported objects in exports.go.
+               // With the textual export format, the list may also include
+               // additional packages that are not strictly required for
+               // import processing alone (they are exported to err "on
+               // the safe side").
+               // TODO(gri) update the want list to be precise, now that
+               // the textual export data is gone.
+               got := fmt.Sprint(pkg.Imports())
+               for _, want := range []string{"go/ast", "go/token"} {
+                       if !strings.Contains(got, want) {
+                               t.Errorf(`Package("exports").Imports() = %s, does not contain %s`, got, want)
+                       }
+               }
+       }
+}
+
+func TestVersionHandling(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       const dir = "./testdata/versions"
+       list, err := ioutil.ReadDir(dir)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       tmpdir := mktmpdir(t)
+       defer os.RemoveAll(tmpdir)
+       corruptdir := filepath.Join(tmpdir, "testdata", "versions")
+       if err := os.Mkdir(corruptdir, 0700); err != nil {
+               t.Fatal(err)
+       }
+
+       for _, f := range list {
+               name := f.Name()
+               if !strings.HasSuffix(name, ".a") {
+                       continue // not a package file
+               }
+               if strings.Contains(name, "corrupted") {
+                       continue // don't process a leftover corrupted file
+               }
+               pkgpath := "./" + name[:len(name)-2]
+
+               if testing.Verbose() {
+                       t.Logf("importing %s", name)
+               }
+
+               // test that export data can be imported
+               _, err := Import(make(map[string]*types2.Package), pkgpath, dir, nil)
+               if err != nil {
+                       // ok to fail if it fails with a no longer supported error for select files
+                       if strings.Contains(err.Error(), "no longer supported") {
+                               switch name {
+                               case "test_go1.7_0.a", "test_go1.7_1.a",
+                                       "test_go1.8_4.a", "test_go1.8_5.a",
+                                       "test_go1.11_6b.a", "test_go1.11_999b.a":
+                                       continue
+                               }
+                               // fall through
+                       }
+                       // ok to fail if it fails with a newer version error for select files
+                       if strings.Contains(err.Error(), "newer version") {
+                               switch name {
+                               case "test_go1.11_999i.a":
+                                       continue
+                               }
+                               // fall through
+                       }
+                       t.Errorf("import %q failed: %v", pkgpath, err)
+                       continue
+               }
+
+               // create file with corrupted export data
+               // 1) read file
+               data, err := ioutil.ReadFile(filepath.Join(dir, name))
+               if err != nil {
+                       t.Fatal(err)
+               }
+               // 2) find export data
+               i := bytes.Index(data, []byte("\n$$B\n")) + 5
+               j := bytes.Index(data[i:], []byte("\n$$\n")) + i
+               if i < 0 || j < 0 || i > j {
+                       t.Fatalf("export data section not found (i = %d, j = %d)", i, j)
+               }
+               // 3) corrupt the data (increment every 7th byte)
+               for k := j - 13; k >= i; k -= 7 {
+                       data[k]++
+               }
+               // 4) write the file
+               pkgpath += "_corrupted"
+               filename := filepath.Join(corruptdir, pkgpath) + ".a"
+               ioutil.WriteFile(filename, data, 0666)
+
+               // test that importing the corrupted file results in an error
+               _, err = Import(make(map[string]*types2.Package), pkgpath, corruptdir, nil)
+               if err == nil {
+                       t.Errorf("import corrupted %q succeeded", pkgpath)
+               } else if msg := err.Error(); !strings.Contains(msg, "version skew") {
+                       t.Errorf("import %q error incorrect (%s)", pkgpath, msg)
+               }
+       }
+}
+
+func TestImportStdLib(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       dt := maxTime
+       if testing.Short() && testenv.Builder() == "" {
+               dt = 10 * time.Millisecond
+       }
+       nimports := testDir(t, "", time.Now().Add(dt)) // installed packages
+       t.Logf("tested %d imports", nimports)
+}
+
+var importedObjectTests = []struct {
+       name string
+       want string
+}{
+       // non-interfaces
+       {"crypto.Hash", "type Hash uint"},
+       {"go/ast.ObjKind", "type ObjKind int"},
+       {"go/types.Qualifier", "type Qualifier func(*Package) string"},
+       {"go/types.Comparable", "func Comparable(T Type) bool"},
+       {"math.Pi", "const Pi untyped float"},
+       {"math.Sin", "func Sin(x float64) float64"},
+       {"go/ast.NotNilFilter", "func NotNilFilter(_ string, v reflect.Value) bool"},
+       {"go/internal/gcimporter.FindPkg", "func FindPkg(path string, srcDir string) (filename string, id string)"},
+
+       // interfaces
+       {"context.Context", "type Context interface{Deadline() (deadline time.Time, ok bool); Done() <-chan struct{}; Err() error; Value(key interface{}) interface{}}"},
+       {"crypto.Decrypter", "type Decrypter interface{Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error); Public() PublicKey}"},
+       {"encoding.BinaryMarshaler", "type BinaryMarshaler interface{MarshalBinary() (data []byte, err error)}"},
+       {"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
+       {"io.ReadWriter", "type ReadWriter interface{Reader; Writer}"},
+       {"go/ast.Node", "type Node interface{End() go/token.Pos; Pos() go/token.Pos}"},
+       // go/types.Type has grown much larger - excluded for now
+       // {"go/types.Type", "type Type interface{String() string; Underlying() Type}"},
+}
+
+func TestImportedTypes(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       for _, test := range importedObjectTests {
+               s := strings.Split(test.name, ".")
+               if len(s) != 2 {
+                       t.Fatal("inconsistent test data")
+               }
+               importPath := s[0]
+               objName := s[1]
+
+               pkg, err := Import(make(map[string]*types2.Package), importPath, ".", nil)
+               if err != nil {
+                       t.Error(err)
+                       continue
+               }
+
+               obj := pkg.Scope().Lookup(objName)
+               if obj == nil {
+                       t.Errorf("%s: object not found", test.name)
+                       continue
+               }
+
+               got := types2.ObjectString(obj, types2.RelativeTo(pkg))
+               if got != test.want {
+                       t.Errorf("%s: got %q; want %q", test.name, got, test.want)
+               }
+
+               if named, _ := obj.Type().(*types2.Named); named != nil {
+                       verifyInterfaceMethodRecvs(t, named, 0)
+               }
+       }
+}
+
+// verifyInterfaceMethodRecvs verifies that method receiver types
+// are named if the methods belong to a named interface type.
+func verifyInterfaceMethodRecvs(t *testing.T, named *types2.Named, level int) {
+       // avoid endless recursion in case of an embedding bug that lead to a cycle
+       if level > 10 {
+               t.Errorf("%s: embeds itself", named)
+               return
+       }
+
+       iface, _ := named.Underlying().(*types2.Interface)
+       if iface == nil {
+               return // not an interface
+       }
+
+       // check explicitly declared methods
+       for i := 0; i < iface.NumExplicitMethods(); i++ {
+               m := iface.ExplicitMethod(i)
+               recv := m.Type().(*types2.Signature).Recv()
+               if recv == nil {
+                       t.Errorf("%s: missing receiver type", m)
+                       continue
+               }
+               if recv.Type() != named {
+                       t.Errorf("%s: got recv type %s; want %s", m, recv.Type(), named)
+               }
+       }
+
+       // check embedded interfaces (if they are named, too)
+       for i := 0; i < iface.NumEmbeddeds(); i++ {
+               // embedding of interfaces cannot have cycles; recursion will terminate
+               if etype, _ := iface.EmbeddedType(i).(*types2.Named); etype != nil {
+                       verifyInterfaceMethodRecvs(t, etype, level+1)
+               }
+       }
+}
+
+func TestIssue5815(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       pkg := importPkg(t, "strings", ".")
+
+       scope := pkg.Scope()
+       for _, name := range scope.Names() {
+               obj := scope.Lookup(name)
+               if obj.Pkg() == nil {
+                       t.Errorf("no pkg for %s", obj)
+               }
+               if tname, _ := obj.(*types2.TypeName); tname != nil {
+                       named := tname.Type().(*types2.Named)
+                       for i := 0; i < named.NumMethods(); i++ {
+                               m := named.Method(i)
+                               if m.Pkg() == nil {
+                                       t.Errorf("no pkg for %s", m)
+                               }
+                       }
+               }
+       }
+}
+
+// Smoke test to ensure that imported methods get the correct package.
+func TestCorrectMethodPackage(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       imports := make(map[string]*types2.Package)
+       _, err := Import(imports, "net/http", ".", nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       mutex := imports["sync"].Scope().Lookup("Mutex").(*types2.TypeName).Type()
+       mset := types2.NewMethodSet(types2.NewPointer(mutex)) // methods of *sync.Mutex
+       sel := mset.Lookup(nil, "Lock")
+       lock := sel.Obj().(*types2.Func)
+       if got, want := lock.Pkg().Path(), "sync"; got != want {
+               t.Errorf("got package path %q; want %q", got, want)
+       }
+}
+
+func TestIssue13566(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       // On windows, we have to set the -D option for the compiler to avoid having a drive
+       // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
+       if runtime.GOOS == "windows" {
+               t.Skip("avoid dealing with relative paths/drive letters on windows")
+       }
+
+       tmpdir := mktmpdir(t)
+       defer os.RemoveAll(tmpdir)
+       testoutdir := filepath.Join(tmpdir, "testdata")
+
+       // b.go needs to be compiled from the output directory so that the compiler can
+       // find the compiled package a. We pass the full path to compile() so that we
+       // don't have to copy the file to that directory.
+       bpath, err := filepath.Abs(filepath.Join("testdata", "b.go"))
+       if err != nil {
+               t.Fatal(err)
+       }
+       compile(t, "testdata", "a.go", testoutdir)
+       compile(t, testoutdir, bpath, testoutdir)
+
+       // import must succeed (test for issue at hand)
+       pkg := importPkg(t, "./testdata/b", tmpdir)
+
+       // make sure all indirectly imported packages have names
+       for _, imp := range pkg.Imports() {
+               if imp.Name() == "" {
+                       t.Errorf("no name for %s package", imp.Path())
+               }
+       }
+}
+
+func TestIssue13898(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       // import go/internal/gcimporter which imports go/types partially
+       imports := make(map[string]*types2.Package)
+       _, err := Import(imports, "go/internal/gcimporter", ".", nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // look for go/types package
+       var goTypesPkg *types2.Package
+       for path, pkg := range imports {
+               if path == "go/types" {
+                       goTypesPkg = pkg
+                       break
+               }
+       }
+       if goTypesPkg == nil {
+               t.Fatal("go/types not found")
+       }
+
+       // look for go/types2.Object type
+       obj := lookupObj(t, goTypesPkg.Scope(), "Object")
+       typ, ok := obj.Type().(*types2.Named)
+       if !ok {
+               t.Fatalf("go/types2.Object type is %v; wanted named type", typ)
+       }
+
+       // lookup go/types2.Object.Pkg method
+       m, index, indirect := types2.LookupFieldOrMethod(typ, false, nil, "Pkg")
+       if m == nil {
+               t.Fatalf("go/types2.Object.Pkg not found (index = %v, indirect = %v)", index, indirect)
+       }
+
+       // the method must belong to go/types
+       if m.Pkg().Path() != "go/types" {
+               t.Fatalf("found %v; want go/types", m.Pkg())
+       }
+}
+
+func TestIssue15517(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       // On windows, we have to set the -D option for the compiler to avoid having a drive
+       // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
+       if runtime.GOOS == "windows" {
+               t.Skip("avoid dealing with relative paths/drive letters on windows")
+       }
+
+       tmpdir := mktmpdir(t)
+       defer os.RemoveAll(tmpdir)
+
+       compile(t, "testdata", "p.go", filepath.Join(tmpdir, "testdata"))
+
+       // Multiple imports of p must succeed without redeclaration errors.
+       // We use an import path that's not cleaned up so that the eventual
+       // file path for the package is different from the package path; this
+       // will expose the error if it is present.
+       //
+       // (Issue: Both the textual and the binary importer used the file path
+       // of the package to be imported as key into the shared packages map.
+       // However, the binary importer then used the package path to identify
+       // the imported package to mark it as complete; effectively marking the
+       // wrong package as complete. By using an "unclean" package path, the
+       // file and package path are different, exposing the problem if present.
+       // The same issue occurs with vendoring.)
+       imports := make(map[string]*types2.Package)
+       for i := 0; i < 3; i++ {
+               if _, err := Import(imports, "./././testdata/p", tmpdir, nil); err != nil {
+                       t.Fatal(err)
+               }
+       }
+}
+
+func TestIssue15920(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       // On windows, we have to set the -D option for the compiler to avoid having a drive
+       // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
+       if runtime.GOOS == "windows" {
+               t.Skip("avoid dealing with relative paths/drive letters on windows")
+       }
+
+       compileAndImportPkg(t, "issue15920")
+}
+
+func TestIssue20046(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       // On windows, we have to set the -D option for the compiler to avoid having a drive
+       // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
+       if runtime.GOOS == "windows" {
+               t.Skip("avoid dealing with relative paths/drive letters on windows")
+       }
+
+       // "./issue20046".V.M must exist
+       pkg := compileAndImportPkg(t, "issue20046")
+       obj := lookupObj(t, pkg.Scope(), "V")
+       if m, index, indirect := types2.LookupFieldOrMethod(obj.Type(), false, nil, "M"); m == nil {
+               t.Fatalf("V.M not found (index = %v, indirect = %v)", index, indirect)
+       }
+}
+func TestIssue25301(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       // On windows, we have to set the -D option for the compiler to avoid having a drive
+       // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
+       if runtime.GOOS == "windows" {
+               t.Skip("avoid dealing with relative paths/drive letters on windows")
+       }
+
+       compileAndImportPkg(t, "issue25301")
+}
+
+func TestIssue25596(t *testing.T) {
+       skipSpecialPlatforms(t)
+
+       // This package only handles gc export data.
+       if runtime.Compiler != "gc" {
+               t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+       }
+
+       // On windows, we have to set the -D option for the compiler to avoid having a drive
+       // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
+       if runtime.GOOS == "windows" {
+               t.Skip("avoid dealing with relative paths/drive letters on windows")
+       }
+
+       compileAndImportPkg(t, "issue25596")
+}
+
+func importPkg(t *testing.T, path, srcDir string) *types2.Package {
+       pkg, err := Import(make(map[string]*types2.Package), path, srcDir, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+       return pkg
+}
+
+func compileAndImportPkg(t *testing.T, name string) *types2.Package {
+       tmpdir := mktmpdir(t)
+       defer os.RemoveAll(tmpdir)
+       compile(t, "testdata", name+".go", filepath.Join(tmpdir, "testdata"))
+       return importPkg(t, "./testdata/"+name, tmpdir)
+}
+
+func lookupObj(t *testing.T, scope *types2.Scope, name string) types2.Object {
+       if obj := scope.Lookup(name); obj != nil {
+               return obj
+       }
+       t.Fatalf("%s not found", name)
+       return nil
+}
diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go
new file mode 100644 (file)
index 0000000..6cb8e93
--- /dev/null
@@ -0,0 +1,624 @@
+// UNREVIEWED
+// Copyright 2018 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.
+
+// Indexed package import.
+// See cmd/compile/internal/gc/iexport.go for the export data format.
+
+package importer
+
+import (
+       "bytes"
+       "cmd/compile/internal/syntax"
+       "cmd/compile/internal/types2"
+       "encoding/binary"
+       "fmt"
+       "go/constant"
+       "go/token"
+       "io"
+       "sort"
+)
+
+type intReader struct {
+       *bytes.Reader
+       path string
+}
+
+func (r *intReader) int64() int64 {
+       i, err := binary.ReadVarint(r.Reader)
+       if err != nil {
+               errorf("import %q: read varint error: %v", r.path, err)
+       }
+       return i
+}
+
+func (r *intReader) uint64() uint64 {
+       i, err := binary.ReadUvarint(r.Reader)
+       if err != nil {
+               errorf("import %q: read varint error: %v", r.path, err)
+       }
+       return i
+}
+
+const predeclReserved = 32
+
+type itag uint64
+
+const (
+       // Types
+       definedType itag = iota
+       pointerType
+       sliceType
+       arrayType
+       chanType
+       mapType
+       signatureType
+       structType
+       interfaceType
+)
+
+const io_SeekCurrent = 1 // io.SeekCurrent (not defined in Go 1.4)
+
+// iImportData imports a package from the serialized package data
+// and returns the number of bytes consumed and a reference to the package.
+// If the export data version is not recognized or the format is otherwise
+// compromised, an error is returned.
+func iImportData(imports map[string]*types2.Package, data []byte, path string) (_ int, pkg *types2.Package, err error) {
+       const currentVersion = 1
+       version := int64(-1)
+       defer func() {
+               if e := recover(); e != nil {
+                       if version > currentVersion {
+                               err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e)
+                       } else {
+                               err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e)
+                       }
+               }
+       }()
+
+       r := &intReader{bytes.NewReader(data), path}
+
+       version = int64(r.uint64())
+       switch version {
+       case currentVersion, 0:
+       default:
+               errorf("unknown iexport format version %d", version)
+       }
+
+       sLen := int64(r.uint64())
+       dLen := int64(r.uint64())
+
+       whence, _ := r.Seek(0, io_SeekCurrent)
+       stringData := data[whence : whence+sLen]
+       declData := data[whence+sLen : whence+sLen+dLen]
+       r.Seek(sLen+dLen, io_SeekCurrent)
+
+       p := iimporter{
+               ipath:   path,
+               version: int(version),
+
+               stringData:  stringData,
+               stringCache: make(map[uint64]string),
+               pkgCache:    make(map[uint64]*types2.Package),
+
+               declData: declData,
+               pkgIndex: make(map[*types2.Package]map[string]uint64),
+               typCache: make(map[uint64]types2.Type),
+       }
+
+       for i, pt := range predeclared {
+               p.typCache[uint64(i)] = pt
+       }
+
+       pkgList := make([]*types2.Package, r.uint64())
+       for i := range pkgList {
+               pkgPathOff := r.uint64()
+               pkgPath := p.stringAt(pkgPathOff)
+               pkgName := p.stringAt(r.uint64())
+               _ = r.uint64() // package height; unused by go/types
+
+               if pkgPath == "" {
+                       pkgPath = path
+               }
+               pkg := imports[pkgPath]
+               if pkg == nil {
+                       pkg = types2.NewPackage(pkgPath, pkgName)
+                       imports[pkgPath] = pkg
+               } else if pkg.Name() != pkgName {
+                       errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path)
+               }
+
+               p.pkgCache[pkgPathOff] = pkg
+
+               nameIndex := make(map[string]uint64)
+               for nSyms := r.uint64(); nSyms > 0; nSyms-- {
+                       name := p.stringAt(r.uint64())
+                       nameIndex[name] = r.uint64()
+               }
+
+               p.pkgIndex[pkg] = nameIndex
+               pkgList[i] = pkg
+       }
+
+       localpkg := pkgList[0]
+
+       names := make([]string, 0, len(p.pkgIndex[localpkg]))
+       for name := range p.pkgIndex[localpkg] {
+               names = append(names, name)
+       }
+       sort.Strings(names)
+       for _, name := range names {
+               p.doDecl(localpkg, name)
+       }
+
+       for _, typ := range p.interfaceList {
+               typ.Complete()
+       }
+
+       // record all referenced packages as imports
+       list := append(([]*types2.Package)(nil), pkgList[1:]...)
+       sort.Sort(byPath(list))
+       localpkg.SetImports(list)
+
+       // package was imported completely and without errors
+       localpkg.MarkComplete()
+
+       consumed, _ := r.Seek(0, io_SeekCurrent)
+       return int(consumed), localpkg, nil
+}
+
+type iimporter struct {
+       ipath   string
+       version int
+
+       stringData  []byte
+       stringCache map[uint64]string
+       pkgCache    map[uint64]*types2.Package
+
+       declData []byte
+       pkgIndex map[*types2.Package]map[string]uint64
+       typCache map[uint64]types2.Type
+
+       interfaceList []*types2.Interface
+}
+
+func (p *iimporter) doDecl(pkg *types2.Package, name string) {
+       // See if we've already imported this declaration.
+       if obj := pkg.Scope().Lookup(name); obj != nil {
+               return
+       }
+
+       off, ok := p.pkgIndex[pkg][name]
+       if !ok {
+               errorf("%v.%v not in index", pkg, name)
+       }
+
+       r := &importReader{p: p, currPkg: pkg}
+       // Reader.Reset is not available in Go 1.4.
+       // Use bytes.NewReader for now.
+       // r.declReader.Reset(p.declData[off:])
+       r.declReader = *bytes.NewReader(p.declData[off:])
+
+       r.obj(name)
+}
+
+func (p *iimporter) stringAt(off uint64) string {
+       if s, ok := p.stringCache[off]; ok {
+               return s
+       }
+
+       slen, n := binary.Uvarint(p.stringData[off:])
+       if n <= 0 {
+               errorf("varint failed")
+       }
+       spos := off + uint64(n)
+       s := string(p.stringData[spos : spos+slen])
+       p.stringCache[off] = s
+       return s
+}
+
+func (p *iimporter) pkgAt(off uint64) *types2.Package {
+       if pkg, ok := p.pkgCache[off]; ok {
+               return pkg
+       }
+       path := p.stringAt(off)
+       errorf("missing package %q in %q", path, p.ipath)
+       return nil
+}
+
+func (p *iimporter) typAt(off uint64, base *types2.Named) types2.Type {
+       if t, ok := p.typCache[off]; ok && (base == nil || !isInterface(t)) {
+               return t
+       }
+
+       if off < predeclReserved {
+               errorf("predeclared type missing from cache: %v", off)
+       }
+
+       r := &importReader{p: p}
+       // Reader.Reset is not available in Go 1.4.
+       // Use bytes.NewReader for now.
+       // r.declReader.Reset(p.declData[off-predeclReserved:])
+       r.declReader = *bytes.NewReader(p.declData[off-predeclReserved:])
+       t := r.doType(base)
+
+       if base == nil || !isInterface(t) {
+               p.typCache[off] = t
+       }
+       return t
+}
+
+type importReader struct {
+       p          *iimporter
+       declReader bytes.Reader
+       currPkg    *types2.Package
+       prevFile   string
+       prevLine   int64
+       prevColumn int64
+}
+
+func (r *importReader) obj(name string) {
+       tag := r.byte()
+       pos := r.pos()
+
+       switch tag {
+       case 'A':
+               typ := r.typ()
+
+               r.declare(types2.NewTypeName(pos, r.currPkg, name, typ))
+
+       case 'C':
+               typ, val := r.value()
+
+               r.declare(types2.NewConst(pos, r.currPkg, name, typ, val))
+
+       case 'F':
+               sig := r.signature(nil)
+
+               r.declare(types2.NewFunc(pos, r.currPkg, name, sig))
+
+       case 'T':
+               // Types can be recursive. We need to setup a stub
+               // declaration before recursing.
+               obj := types2.NewTypeName(pos, r.currPkg, name, nil)
+               named := types2.NewNamed(obj, nil, nil)
+               r.declare(obj)
+
+               underlying := r.p.typAt(r.uint64(), named).Underlying()
+               named.SetUnderlying(underlying)
+
+               if !isInterface(underlying) {
+                       for n := r.uint64(); n > 0; n-- {
+                               mpos := r.pos()
+                               mname := r.ident()
+                               recv := r.param()
+                               msig := r.signature(recv)
+
+                               named.AddMethod(types2.NewFunc(mpos, r.currPkg, mname, msig))
+                       }
+               }
+
+       case 'V':
+               typ := r.typ()
+
+               r.declare(types2.NewVar(pos, r.currPkg, name, typ))
+
+       default:
+               errorf("unexpected tag: %v", tag)
+       }
+}
+
+func (r *importReader) declare(obj types2.Object) {
+       obj.Pkg().Scope().Insert(obj)
+}
+
+func (r *importReader) value() (typ types2.Type, val constant.Value) {
+       typ = r.typ()
+
+       switch b := typ.Underlying().(*types2.Basic); b.Info() & types2.IsConstType {
+       case types2.IsBoolean:
+               val = constant.MakeBool(r.bool())
+
+       case types2.IsString:
+               val = constant.MakeString(r.string())
+
+       case types2.IsInteger:
+               val = r.mpint(b)
+
+       case types2.IsFloat:
+               val = r.mpfloat(b)
+
+       case types2.IsComplex:
+               re := r.mpfloat(b)
+               im := r.mpfloat(b)
+               val = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
+
+       default:
+               errorf("unexpected type %v", typ) // panics
+               panic("unreachable")
+       }
+
+       return
+}
+
+func intSize(b *types2.Basic) (signed bool, maxBytes uint) {
+       if (b.Info() & types2.IsUntyped) != 0 {
+               return true, 64
+       }
+
+       switch b.Kind() {
+       case types2.Float32, types2.Complex64:
+               return true, 3
+       case types2.Float64, types2.Complex128:
+               return true, 7
+       }
+
+       signed = (b.Info() & types2.IsUnsigned) == 0
+       switch b.Kind() {
+       case types2.Int8, types2.Uint8:
+               maxBytes = 1
+       case types2.Int16, types2.Uint16:
+               maxBytes = 2
+       case types2.Int32, types2.Uint32:
+               maxBytes = 4
+       default:
+               maxBytes = 8
+       }
+
+       return
+}
+
+func (r *importReader) mpint(b *types2.Basic) constant.Value {
+       signed, maxBytes := intSize(b)
+
+       maxSmall := 256 - maxBytes
+       if signed {
+               maxSmall = 256 - 2*maxBytes
+       }
+       if maxBytes == 1 {
+               maxSmall = 256
+       }
+
+       n, _ := r.declReader.ReadByte()
+       if uint(n) < maxSmall {
+               v := int64(n)
+               if signed {
+                       v >>= 1
+                       if n&1 != 0 {
+                               v = ^v
+                       }
+               }
+               return constant.MakeInt64(v)
+       }
+
+       v := -n
+       if signed {
+               v = -(n &^ 1) >> 1
+       }
+       if v < 1 || uint(v) > maxBytes {
+               errorf("weird decoding: %v, %v => %v", n, signed, v)
+       }
+
+       buf := make([]byte, v)
+       io.ReadFull(&r.declReader, buf)
+
+       // convert to little endian
+       // TODO(gri) go/constant should have a more direct conversion function
+       //           (e.g., once it supports a big.Float based implementation)
+       for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
+               buf[i], buf[j] = buf[j], buf[i]
+       }
+
+       x := constant.MakeFromBytes(buf)
+       if signed && n&1 != 0 {
+               x = constant.UnaryOp(token.SUB, x, 0)
+       }
+       return x
+}
+
+func (r *importReader) mpfloat(b *types2.Basic) constant.Value {
+       x := r.mpint(b)
+       if constant.Sign(x) == 0 {
+               return x
+       }
+
+       exp := r.int64()
+       switch {
+       case exp > 0:
+               x = constant.Shift(x, token.SHL, uint(exp))
+       case exp < 0:
+               d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp))
+               x = constant.BinaryOp(x, token.QUO, d)
+       }
+       return x
+}
+
+func (r *importReader) ident() string {
+       return r.string()
+}
+
+func (r *importReader) qualifiedIdent() (*types2.Package, string) {
+       name := r.string()
+       pkg := r.pkg()
+       return pkg, name
+}
+
+func (r *importReader) pos() syntax.Pos {
+       if r.p.version >= 1 {
+               r.posv1()
+       } else {
+               r.posv0()
+       }
+
+       if r.prevFile == "" && r.prevLine == 0 && r.prevColumn == 0 {
+               return syntax.Pos{}
+       }
+       // TODO(gri) fix this
+       // return r.p.fake.pos(r.prevFile, int(r.prevLine), int(r.prevColumn))
+       return syntax.Pos{}
+}
+
+func (r *importReader) posv0() {
+       delta := r.int64()
+       if delta != deltaNewFile {
+               r.prevLine += delta
+       } else if l := r.int64(); l == -1 {
+               r.prevLine += deltaNewFile
+       } else {
+               r.prevFile = r.string()
+               r.prevLine = l
+       }
+}
+
+func (r *importReader) posv1() {
+       delta := r.int64()
+       r.prevColumn += delta >> 1
+       if delta&1 != 0 {
+               delta = r.int64()
+               r.prevLine += delta >> 1
+               if delta&1 != 0 {
+                       r.prevFile = r.string()
+               }
+       }
+}
+
+func (r *importReader) typ() types2.Type {
+       return r.p.typAt(r.uint64(), nil)
+}
+
+func isInterface(t types2.Type) bool {
+       _, ok := t.(*types2.Interface)
+       return ok
+}
+
+func (r *importReader) pkg() *types2.Package { return r.p.pkgAt(r.uint64()) }
+func (r *importReader) string() string       { return r.p.stringAt(r.uint64()) }
+
+func (r *importReader) doType(base *types2.Named) types2.Type {
+       switch k := r.kind(); k {
+       default:
+               errorf("unexpected kind tag in %q: %v", r.p.ipath, k)
+               return nil
+
+       case definedType:
+               pkg, name := r.qualifiedIdent()
+               r.p.doDecl(pkg, name)
+               return pkg.Scope().Lookup(name).(*types2.TypeName).Type()
+       case pointerType:
+               return types2.NewPointer(r.typ())
+       case sliceType:
+               return types2.NewSlice(r.typ())
+       case arrayType:
+               n := r.uint64()
+               return types2.NewArray(r.typ(), int64(n))
+       case chanType:
+               dir := chanDir(int(r.uint64()))
+               return types2.NewChan(dir, r.typ())
+       case mapType:
+               return types2.NewMap(r.typ(), r.typ())
+       case signatureType:
+               r.currPkg = r.pkg()
+               return r.signature(nil)
+
+       case structType:
+               r.currPkg = r.pkg()
+
+               fields := make([]*types2.Var, r.uint64())
+               tags := make([]string, len(fields))
+               for i := range fields {
+                       fpos := r.pos()
+                       fname := r.ident()
+                       ftyp := r.typ()
+                       emb := r.bool()
+                       tag := r.string()
+
+                       fields[i] = types2.NewField(fpos, r.currPkg, fname, ftyp, emb)
+                       tags[i] = tag
+               }
+               return types2.NewStruct(fields, tags)
+
+       case interfaceType:
+               r.currPkg = r.pkg()
+
+               embeddeds := make([]types2.Type, r.uint64())
+               for i := range embeddeds {
+                       _ = r.pos()
+                       embeddeds[i] = r.typ()
+               }
+
+               methods := make([]*types2.Func, r.uint64())
+               for i := range methods {
+                       mpos := r.pos()
+                       mname := r.ident()
+
+                       // TODO(mdempsky): Matches bimport.go, but I
+                       // don't agree with this.
+                       var recv *types2.Var
+                       if base != nil {
+                               recv = types2.NewVar(syntax.Pos{}, r.currPkg, "", base)
+                       }
+
+                       msig := r.signature(recv)
+                       methods[i] = types2.NewFunc(mpos, r.currPkg, mname, msig)
+               }
+
+               typ := types2.NewInterfaceType(methods, embeddeds)
+               r.p.interfaceList = append(r.p.interfaceList, typ)
+               return typ
+       }
+}
+
+func (r *importReader) kind() itag {
+       return itag(r.uint64())
+}
+
+func (r *importReader) signature(recv *types2.Var) *types2.Signature {
+       params := r.paramList()
+       results := r.paramList()
+       variadic := params.Len() > 0 && r.bool()
+       return types2.NewSignature(recv, params, results, variadic)
+}
+
+func (r *importReader) paramList() *types2.Tuple {
+       xs := make([]*types2.Var, r.uint64())
+       for i := range xs {
+               xs[i] = r.param()
+       }
+       return types2.NewTuple(xs...)
+}
+
+func (r *importReader) param() *types2.Var {
+       pos := r.pos()
+       name := r.ident()
+       typ := r.typ()
+       return types2.NewParam(pos, r.currPkg, name, typ)
+}
+
+func (r *importReader) bool() bool {
+       return r.uint64() != 0
+}
+
+func (r *importReader) int64() int64 {
+       n, err := binary.ReadVarint(&r.declReader)
+       if err != nil {
+               errorf("readVarint: %v", err)
+       }
+       return n
+}
+
+func (r *importReader) uint64() uint64 {
+       n, err := binary.ReadUvarint(&r.declReader)
+       if err != nil {
+               errorf("readUvarint: %v", err)
+       }
+       return n
+}
+
+func (r *importReader) byte() byte {
+       x, err := r.declReader.ReadByte()
+       if err != nil {
+               errorf("declReader.ReadByte: %v", err)
+       }
+       return x
+}
diff --git a/src/cmd/compile/internal/importer/support.go b/src/cmd/compile/internal/importer/support.go
new file mode 100644 (file)
index 0000000..4f013f4
--- /dev/null
@@ -0,0 +1,144 @@
+// UNREVIEWED
+// Copyright 2015 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.
+
+// This file implements support functionality for iimport.go.
+
+package importer
+
+import (
+       "cmd/compile/internal/types2"
+       "fmt"
+       "go/token"
+       "sync"
+)
+
+func errorf(format string, args ...interface{}) {
+       panic(fmt.Sprintf(format, args...))
+}
+
+const deltaNewFile = -64 // see cmd/compile/internal/gc/bexport.go
+
+// Synthesize a token.Pos
+type fakeFileSet struct {
+       fset  *token.FileSet
+       files map[string]*token.File
+}
+
+func (s *fakeFileSet) pos(file string, line, column int) token.Pos {
+       // TODO(mdempsky): Make use of column.
+
+       // Since we don't know the set of needed file positions, we
+       // reserve maxlines positions per file.
+       const maxlines = 64 * 1024
+       f := s.files[file]
+       if f == nil {
+               f = s.fset.AddFile(file, -1, maxlines)
+               s.files[file] = f
+               // Allocate the fake linebreak indices on first use.
+               // TODO(adonovan): opt: save ~512KB using a more complex scheme?
+               fakeLinesOnce.Do(func() {
+                       fakeLines = make([]int, maxlines)
+                       for i := range fakeLines {
+                               fakeLines[i] = i
+                       }
+               })
+               f.SetLines(fakeLines)
+       }
+
+       if line > maxlines {
+               line = 1
+       }
+
+       // Treat the file as if it contained only newlines
+       // and column=1: use the line number as the offset.
+       return f.Pos(line - 1)
+}
+
+var (
+       fakeLines     []int
+       fakeLinesOnce sync.Once
+)
+
+func chanDir(d int) types2.ChanDir {
+       // tag values must match the constants in cmd/compile/internal/gc/go.go
+       switch d {
+       case 1 /* Crecv */ :
+               return types2.RecvOnly
+       case 2 /* Csend */ :
+               return types2.SendOnly
+       case 3 /* Cboth */ :
+               return types2.SendRecv
+       default:
+               errorf("unexpected channel dir %d", d)
+               return 0
+       }
+}
+
+var predeclared = []types2.Type{
+       // basic types
+       types2.Typ[types2.Bool],
+       types2.Typ[types2.Int],
+       types2.Typ[types2.Int8],
+       types2.Typ[types2.Int16],
+       types2.Typ[types2.Int32],
+       types2.Typ[types2.Int64],
+       types2.Typ[types2.Uint],
+       types2.Typ[types2.Uint8],
+       types2.Typ[types2.Uint16],
+       types2.Typ[types2.Uint32],
+       types2.Typ[types2.Uint64],
+       types2.Typ[types2.Uintptr],
+       types2.Typ[types2.Float32],
+       types2.Typ[types2.Float64],
+       types2.Typ[types2.Complex64],
+       types2.Typ[types2.Complex128],
+       types2.Typ[types2.String],
+
+       // basic type aliases
+       types2.Universe.Lookup("byte").Type(),
+       types2.Universe.Lookup("rune").Type(),
+
+       // error
+       types2.Universe.Lookup("error").Type(),
+
+       // untyped types
+       types2.Typ[types2.UntypedBool],
+       types2.Typ[types2.UntypedInt],
+       types2.Typ[types2.UntypedRune],
+       types2.Typ[types2.UntypedFloat],
+       types2.Typ[types2.UntypedComplex],
+       types2.Typ[types2.UntypedString],
+       types2.Typ[types2.UntypedNil],
+
+       // package unsafe
+       types2.Typ[types2.UnsafePointer],
+
+       // invalid type
+       types2.Typ[types2.Invalid], // only appears in packages with errors
+
+       // used internally by gc; never used by this package or in .a files
+       anyType{},
+}
+
+type anyType struct{}
+
+func (t anyType) Underlying() types2.Type { return t }
+func (t anyType) Under() types2.Type      { return t }
+func (t anyType) String() string          { return "any" }
+
+// types2.aType is not exported for now so we need to implemented these here.
+func (anyType) Basic() *types2.Basic         { return nil }
+func (anyType) Array() *types2.Array         { return nil }
+func (anyType) Slice() *types2.Slice         { return nil }
+func (anyType) Struct() *types2.Struct       { return nil }
+func (anyType) Pointer() *types2.Pointer     { return nil }
+func (anyType) Tuple() *types2.Tuple         { return nil }
+func (anyType) Signature() *types2.Signature { return nil }
+func (anyType) Sum() *types2.Sum             { return nil }
+func (anyType) Interface() *types2.Interface { return nil }
+func (anyType) Map() *types2.Map             { return nil }
+func (anyType) Chan() *types2.Chan           { return nil }
+func (anyType) Named() *types2.Named         { return nil }
+func (anyType) TypeParam() *types2.TypeParam { return nil }
diff --git a/src/cmd/compile/internal/importer/testdata/a.go b/src/cmd/compile/internal/importer/testdata/a.go
new file mode 100644 (file)
index 0000000..06dafee
--- /dev/null
@@ -0,0 +1,15 @@
+// UNREVIEWED
+// Copyright 2016 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.
+
+// Input for TestIssue13566
+
+package a
+
+import "encoding/json"
+
+type A struct {
+       a    *A
+       json json.RawMessage
+}
diff --git a/src/cmd/compile/internal/importer/testdata/b.go b/src/cmd/compile/internal/importer/testdata/b.go
new file mode 100644 (file)
index 0000000..a601dbc
--- /dev/null
@@ -0,0 +1,12 @@
+// UNREVIEWED
+// Copyright 2016 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.
+
+// Input for TestIssue13566
+
+package b
+
+import "./a"
+
+type A a.A
diff --git a/src/cmd/compile/internal/importer/testdata/exports.go b/src/cmd/compile/internal/importer/testdata/exports.go
new file mode 100644 (file)
index 0000000..2a720fd
--- /dev/null
@@ -0,0 +1,89 @@
+// UNREVIEWED
+// Copyright 2011 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.
+
+// This file is used to generate an object file which
+// serves as test file for gcimporter_test.go.
+
+package exports
+
+import "go/ast"
+
+// Issue 3682: Correctly read dotted identifiers from export data.
+const init1 = 0
+
+func init() {}
+
+const (
+       C0 int = 0
+       C1     = 3.14159265
+       C2     = 2.718281828i
+       C3     = -123.456e-789
+       C4     = +123.456e+789
+       C5     = 1234i
+       C6     = "foo\n"
+       C7     = `bar\n`
+)
+
+type (
+       T1  int
+       T2  [10]int
+       T3  []int
+       T4  *int
+       T5  chan int
+       T6a chan<- int
+       T6b chan (<-chan int)
+       T6c chan<- (chan int)
+       T7  <-chan *ast.File
+       T8  struct{}
+       T9  struct {
+               a    int
+               b, c float32
+               d    []string `go:"tag"`
+       }
+       T10 struct {
+               T8
+               T9
+               _ *T10
+       }
+       T11 map[int]string
+       T12 interface{}
+       T13 interface {
+               m1()
+               m2(int) float32
+       }
+       T14 interface {
+               T12
+               T13
+               m3(x ...struct{}) []T9
+       }
+       T15 func()
+       T16 func(int)
+       T17 func(x int)
+       T18 func() float32
+       T19 func() (x float32)
+       T20 func(...interface{})
+       T21 struct{ next *T21 }
+       T22 struct{ link *T23 }
+       T23 struct{ link *T22 }
+       T24 *T24
+       T25 *T26
+       T26 *T27
+       T27 *T25
+       T28 func(T28) T28
+)
+
+var (
+       V0 int
+       V1         = -991.0
+       V2 float32 = 1.2
+)
+
+func F1()         {}
+func F2(x int)    {}
+func F3() int     { return 0 }
+func F4() float32 { return 0 }
+func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10)
+
+func (p *T1) M1()
diff --git a/src/cmd/compile/internal/importer/testdata/issue15920.go b/src/cmd/compile/internal/importer/testdata/issue15920.go
new file mode 100644 (file)
index 0000000..b402026
--- /dev/null
@@ -0,0 +1,12 @@
+// UNREVIEWED
+// Copyright 2016 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
+
+// The underlying type of Error is the underlying type of error.
+// Make sure we can import this again without problems.
+type Error error
+
+func F() Error { return nil }
diff --git a/src/cmd/compile/internal/importer/testdata/issue20046.go b/src/cmd/compile/internal/importer/testdata/issue20046.go
new file mode 100644 (file)
index 0000000..e412f35
--- /dev/null
@@ -0,0 +1,10 @@
+// UNREVIEWED
+// Copyright 2017 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 V interface {
+       M()
+}
diff --git a/src/cmd/compile/internal/importer/testdata/issue25301.go b/src/cmd/compile/internal/importer/testdata/issue25301.go
new file mode 100644 (file)
index 0000000..a9dc1d7
--- /dev/null
@@ -0,0 +1,18 @@
+// UNREVIEWED
+// Copyright 2018 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 issue25301
+
+type (
+       A = interface {
+               M()
+       }
+       T interface {
+               A
+       }
+       S struct{}
+)
+
+func (S) M() { println("m") }
diff --git a/src/cmd/compile/internal/importer/testdata/issue25596.go b/src/cmd/compile/internal/importer/testdata/issue25596.go
new file mode 100644 (file)
index 0000000..95bef42
--- /dev/null
@@ -0,0 +1,14 @@
+// UNREVIEWED
+// Copyright 2018 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 issue25596
+
+type E interface {
+       M() T
+}
+
+type T interface {
+       E
+}
diff --git a/src/cmd/compile/internal/importer/testdata/p.go b/src/cmd/compile/internal/importer/testdata/p.go
new file mode 100644 (file)
index 0000000..34a20ea
--- /dev/null
@@ -0,0 +1,14 @@
+// UNREVIEWED
+// Copyright 2016 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.
+
+// Input for TestIssue15517
+
+package p
+
+const C = 0
+
+var V int
+
+func F() {}
diff --git a/src/cmd/compile/internal/importer/testdata/versions/test.go b/src/cmd/compile/internal/importer/testdata/versions/test.go
new file mode 100644 (file)
index 0000000..2f8eb5c
--- /dev/null
@@ -0,0 +1,29 @@
+// UNREVIEWED
+// Copyright 2016 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.
+
+// To create a test case for a new export format version,
+// build this package with the latest compiler and store
+// the resulting .a file appropriately named in the versions
+// directory. The VersionHandling test will pick it up.
+//
+// In the testdata/versions:
+//
+// go build -o test_go1.$X_$Y.a test.go
+//
+// with $X = Go version and $Y = export format version
+// (add 'b' or 'i' to distinguish between binary and
+// indexed format starting with 1.11 as long as both
+// formats are supported).
+//
+// Make sure this source is extended such that it exercises
+// whatever export format change has taken place.
+
+package test
+
+// Any release before and including Go 1.7 didn't encode
+// the package for a blank struct field.
+type BlankField struct {
+       _ int
+}
index 72b1ad6333de12157ee8d616554da97e2df2c3ba..919667f1d311d261ee8e68151afc259cfa8ee56a 100644 (file)
@@ -128,6 +128,10 @@ func testSyntaxErrors(t *testing.T, filename string) {
        }
        defer f.Close()
 
+       var mode Mode
+       if strings.HasSuffix(filename, ".go2") {
+               mode = AllowGenerics
+       }
        ParseFile(filename, func(err error) {
                e, ok := err.(Error)
                if !ok {
@@ -162,7 +166,7 @@ func testSyntaxErrors(t *testing.T, filename string) {
                } else {
                        t.Errorf("%s: unexpected error: %s", orig, e.Msg)
                }
-       }, nil, 0)
+       }, nil, mode)
 
        if *print {
                fmt.Println()
index 487cab19fef9cd6afc5efd50fe4c4de72781d0b0..a06d6e85b1e82987bba07a557a7567794085c801 100644 (file)
@@ -37,7 +37,7 @@ type File struct {
        Pragma   Pragma
        PkgName  *Name
        DeclList []Decl
-       Lines    uint
+       EOF      Pos
        node
 }
 
@@ -55,8 +55,8 @@ type (
        ImportDecl struct {
                Group        *Group // nil means not part of a group
                Pragma       Pragma
-               LocalPkgName *Name // including "."; nil means no rename present
-               Path         *BasicLit
+               LocalPkgName *Name     // including "."; nil means no rename present
+               Path         *BasicLit // Path.Bad || Path.Kind == StringLit; nil means no path
                decl
        }
 
@@ -74,11 +74,12 @@ type (
 
        // Name Type
        TypeDecl struct {
-               Group  *Group // nil means not part of a group
-               Pragma Pragma
-               Name   *Name
-               Alias  bool
-               Type   Expr
+               Group      *Group // nil means not part of a group
+               Pragma     Pragma
+               Name       *Name
+               TParamList []*Field // nil means no type parameters
+               Alias      bool
+               Type       Expr
                decl
        }
 
@@ -99,11 +100,12 @@ type (
        // func Receiver Name Type { Body }
        // func Receiver Name Type
        FuncDecl struct {
-               Pragma Pragma
-               Recv   *Field // nil means regular function
-               Name   *Name
-               Type   *FuncType
-               Body   *BlockStmt // nil means no body (forward declaration)
+               Pragma     Pragma
+               Recv       *Field // nil means regular function
+               Name       *Name
+               TParamList []*Field // nil means no type parameters
+               Type       *FuncType
+               Body       *BlockStmt // nil means no body (forward declaration)
                decl
        }
 )
@@ -120,6 +122,13 @@ type Group struct {
 // ----------------------------------------------------------------------------
 // Expressions
 
+func NewName(pos Pos, value string) *Name {
+       n := new(Name)
+       n.pos = pos
+       n.Value = value
+       return n
+}
+
 type (
        Expr interface {
                Node
@@ -182,6 +191,7 @@ type (
        }
 
        // X[Index]
+       // X[T1, T2, ...] (with Ti = Index.(*ListExpr).ElemList[i])
        IndexExpr struct {
                X     Expr
                Index Expr
@@ -272,7 +282,7 @@ type (
 
        // interface { MethodList[0]; MethodList[1]; ... }
        InterfaceType struct {
-               MethodList []*Field
+               MethodList []*Field // a field named "type" means a type constraint
                expr
        }
 
index 1485b700596aa47617dd92453ba23881d7855ce3..e3fb1003a291c8347bcea8fe578505ca4aa1adeb 100644 (file)
@@ -445,7 +445,7 @@ func (p *parser) fileOrNil() *File {
        // p.tok == _EOF
 
        p.clearPragma()
-       f.Lines = p.line
+       f.EOF = p.pos()
 
        return f
 }
@@ -458,21 +458,22 @@ func isEmptyFuncDecl(dcl Decl) bool {
 // ----------------------------------------------------------------------------
 // Declarations
 
-// list parses a possibly empty, sep-separated list, optionally
-// followed by sep and enclosed by ( and ) or { and }. open is
-// one of _Lparen, or _Lbrace, sep is one of _Comma or _Semi,
-// and close is expected to be the (closing) opposite of open.
-// For each list element, f is called. After f returns true, no
-// more list elements are accepted. list returns the position
-// of the closing token.
+// list parses a possibly empty, sep-separated list of elements, optionally
+// followed by sep, and closed by close (or EOF). sep must be one of _Comma
+// or _Semi, and close must be one of _Rparen, _Rbrace, or _Rbrack.
 //
-// list = "(" { f sep } ")" |
-//        "{" { f sep } "}" . // sep is optional before ")" or "}"
+// For each list element, f is called. Specifically, unless we're at close
+// (or EOF), f is called at least once. After f returns true, no more list
+// elements are accepted. list returns the position of the closing token.
 //
-func (p *parser) list(open, sep, close token, f func() bool) Pos {
-       p.want(open)
+// list = [ f { sep f } [sep] ] close .
+//
+func (p *parser) list(sep, close token, f func() bool) Pos {
+       if debug && (sep != _Comma && sep != _Semi || close != _Rparen && close != _Rbrace && close != _Rbrack) {
+               panic("invalid sep or close argument for list")
+       }
 
-       var done bool
+       done := false
        for p.tok != _EOF && p.tok != close && !done {
                done = f()
                // sep is optional before close
@@ -496,22 +497,18 @@ func (p *parser) appendGroup(list []Decl, f func(*Group) Decl) []Decl {
        if p.tok == _Lparen {
                g := new(Group)
                p.clearPragma()
-               p.list(_Lparen, _Semi, _Rparen, func() bool {
-                       list = append(list, f(g))
+               p.next() // must consume "(" after calling clearPragma!
+               p.list(_Semi, _Rparen, func() bool {
+                       if x := f(g); x != nil {
+                               list = append(list, x)
+                       }
                        return false
                })
        } else {
-               list = append(list, f(nil))
-       }
-
-       if debug {
-               for _, d := range list {
-                       if d == nil {
-                               panic("nil list entry")
-                       }
+               if x := f(nil); x != nil {
+                       list = append(list, x)
                }
        }
-
        return list
 }
 
@@ -531,15 +528,20 @@ func (p *parser) importDecl(group *Group) Decl {
        case _Name:
                d.LocalPkgName = p.name()
        case _Dot:
-               d.LocalPkgName = p.newName(".")
+               d.LocalPkgName = NewName(p.pos(), ".")
                p.next()
        }
        d.Path = p.oliteral()
        if d.Path == nil {
                p.syntaxError("missing import path")
                p.advance(_Semi, _Rparen)
-               return nil
+               return d
+       }
+       if !d.Path.Bad && d.Path.Kind != StringLit {
+               p.syntaxError("import path must be a string")
+               d.Path.Bad = true
        }
+       // d.Path.Bad || d.Path.Kind == StringLit
 
        return d
 }
@@ -566,7 +568,7 @@ func (p *parser) constDecl(group *Group) Decl {
        return d
 }
 
-// TypeSpec = identifier [ "=" ] Type .
+// TypeSpec = identifier [ TypeParams ] [ "=" ] Type .
 func (p *parser) typeDecl(group *Group) Decl {
        if trace {
                defer p.trace("typeDecl")()
@@ -578,8 +580,42 @@ func (p *parser) typeDecl(group *Group) Decl {
        d.Pragma = p.takePragma()
 
        d.Name = p.name()
-       d.Alias = p.gotAssign()
-       d.Type = p.typeOrNil()
+       if p.tok == _Lbrack {
+               // array/slice or generic type
+               pos := p.pos()
+               p.next()
+               switch p.tok {
+               case _Rbrack:
+                       p.next()
+                       d.Type = p.sliceType(pos)
+               case _Name:
+                       // array or generic type
+                       p.xnest++
+                       x := p.expr()
+                       p.xnest--
+                       if name0, ok := x.(*Name); p.mode&AllowGenerics != 0 && ok && p.tok != _Rbrack {
+                               // generic type
+                               d.TParamList = p.paramList(name0, _Rbrack, true)
+                               pos := p.pos()
+                               if p.gotAssign() {
+                                       p.syntaxErrorAt(pos, "generic type cannot be alias")
+                               }
+                               d.Type = p.typeOrNil()
+                       } else {
+                               // x is the array length expression
+                               if debug && x == nil {
+                                       panic("internal error: nil expression")
+                               }
+                               d.Type = p.arrayType(pos, x)
+                       }
+               default:
+                       d.Type = p.arrayType(pos, nil)
+               }
+       } else {
+               d.Alias = p.gotAssign()
+               d.Type = p.typeOrNil()
+       }
+
        if d.Type == nil {
                d.Type = p.badExpr()
                p.syntaxError("in type declaration")
@@ -613,7 +649,7 @@ func (p *parser) varDecl(group *Group) Decl {
        return d
 }
 
-// FunctionDecl = "func" FunctionName ( Function | Signature ) .
+// FunctionDecl = "func" FunctionName [ TypeParams ] ( Function | Signature ) .
 // FunctionName = identifier .
 // Function     = Signature FunctionBody .
 // MethodDecl   = "func" Receiver MethodName ( Function | Signature ) .
@@ -627,8 +663,8 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
        f.pos = p.pos()
        f.Pragma = p.takePragma()
 
-       if p.tok == _Lparen {
-               rcvr := p.paramList()
+       if p.got(_Lparen) {
+               rcvr := p.paramList(nil, _Rparen, false)
                switch len(rcvr) {
                case 0:
                        p.error("method has no receiver")
@@ -647,6 +683,14 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
        }
 
        f.Name = p.name()
+       if p.mode&AllowGenerics != 0 && p.got(_Lbrack) {
+               if p.tok == _Rbrack {
+                       p.syntaxError("empty type parameter list")
+                       p.next()
+               } else {
+                       f.TParamList = p.paramList(nil, _Rbrack, true)
+               }
+       }
        f.Type = p.funcType()
        if p.tok == _Lbrace {
                f.Body = p.funcBody()
@@ -850,13 +894,7 @@ func (p *parser) operand(keep_parens bool) Expr {
                // Optimization: Record presence of ()'s only where needed
                // for error reporting. Don't bother in other cases; it is
                // just a waste of memory and time.
-
-               // Parentheses are not permitted on lhs of := .
-               // switch x.Op {
-               // case ONAME, ONONAME, OPACK, OTYPE, OLITERAL, OTYPESW:
-               //      keep_parens = true
-               // }
-
+               //
                // Parentheses are not permitted around T in a composite
                // literal T{}. If the next token is a {, assume x is a
                // composite literal type T (it may not be, { could be
@@ -879,19 +917,19 @@ func (p *parser) operand(keep_parens bool) Expr {
        case _Func:
                pos := p.pos()
                p.next()
-               t := p.funcType()
+               ftyp := p.funcType()
                if p.tok == _Lbrace {
                        p.xnest++
 
                        f := new(FuncLit)
                        f.pos = pos
-                       f.Type = t
+                       f.Type = ftyp
                        f.Body = p.funcBody()
 
                        p.xnest--
                        return f
                }
-               return t
+               return ftyp
 
        case _Lbrack, _Chan, _Map, _Struct, _Interface:
                return p.type_() // othertype
@@ -971,29 +1009,52 @@ loop:
 
                case _Lbrack:
                        p.next()
-                       p.xnest++
+
+                       if p.tok == _Rbrack {
+                               // invalid empty instance, slice or index expression; accept but complain
+                               p.syntaxError("expecting operand")
+                               p.next()
+                               break
+                       }
 
                        var i Expr
                        if p.tok != _Colon {
-                               i = p.expr()
-                               if p.got(_Rbrack) {
-                                       // x[i]
-                                       t := new(IndexExpr)
-                                       t.pos = pos
-                                       t.X = x
-                                       t.Index = i
-                                       x = t
+                               if p.mode&AllowGenerics == 0 {
+                                       p.xnest++
+                                       i = p.expr()
                                        p.xnest--
-                                       break
+                                       if p.got(_Rbrack) {
+                                               // x[i]
+                                               t := new(IndexExpr)
+                                               t.pos = pos
+                                               t.X = x
+                                               t.Index = i
+                                               x = t
+                                               break
+                                       }
+                               } else {
+                                       var comma bool
+                                       i, comma = p.typeList()
+                                       if comma || p.tok == _Rbrack {
+                                               p.want(_Rbrack)
+                                               // x[i,] or x[i, j, ...]
+                                               t := new(IndexExpr)
+                                               t.pos = pos
+                                               t.X = x
+                                               t.Index = i
+                                               x = t
+                                               break
+                                       }
                                }
                        }
 
                        // x[i:...
+                       p.want(_Colon)
+                       p.xnest++
                        t := new(SliceExpr)
                        t.pos = pos
                        t.X = x
                        t.Index[0] = i
-                       p.want(_Colon)
                        if p.tok != _Colon && p.tok != _Rbrack {
                                // x[i:j...
                                t.Index[1] = p.expr()
@@ -1014,14 +1075,14 @@ loop:
                                        t.Index[2] = p.badExpr()
                                }
                        }
+                       p.xnest--
                        p.want(_Rbrack)
-
                        x = t
-                       p.xnest--
 
                case _Lparen:
                        t := new(CallExpr)
                        t.pos = pos
+                       p.next()
                        t.Fun = x
                        t.ArgList, t.HasDots = p.argList()
                        x = t
@@ -1035,7 +1096,12 @@ loop:
                        switch t.(type) {
                        case *Name, *SelectorExpr:
                                if p.xnest >= 0 {
-                                       // x is considered a composite literal type
+                                       // x is possibly a composite literal type
+                                       complit_ok = true
+                               }
+                       case *IndexExpr:
+                               if p.xnest >= 0 {
+                                       // x is possibly a composite literal type
                                        complit_ok = true
                                }
                        case *ArrayType, *SliceType, *StructType, *MapType:
@@ -1085,7 +1151,8 @@ func (p *parser) complitexpr() *CompositeLit {
        x.pos = p.pos()
 
        p.xnest++
-       x.Rbrace = p.list(_Lbrace, _Comma, _Rbrace, func() bool {
+       p.want(_Lbrace)
+       x.Rbrace = p.list(_Comma, _Rbrace, func() bool {
                // value
                e := p.bare_complitexpr()
                if p.tok == _Colon {
@@ -1170,26 +1237,10 @@ func (p *parser) typeOrNil() Expr {
                // '[' oexpr ']' ntype
                // '[' _DotDotDot ']' ntype
                p.next()
-               p.xnest++
                if p.got(_Rbrack) {
-                       // []T
-                       p.xnest--
-                       t := new(SliceType)
-                       t.pos = pos
-                       t.Elem = p.type_()
-                       return t
+                       return p.sliceType(pos)
                }
-
-               // [n]T
-               t := new(ArrayType)
-               t.pos = pos
-               if !p.got(_DotDotDot) {
-                       t.Len = p.expr()
-               }
-               p.want(_Rbrack)
-               p.xnest--
-               t.Elem = p.type_()
-               return t
+               return p.arrayType(pos, nil)
 
        case _Chan:
                // _Chan non_recvchantype
@@ -1221,7 +1272,7 @@ func (p *parser) typeOrNil() Expr {
                return p.interfaceType()
 
        case _Name:
-               return p.dotname(p.name())
+               return p.qualifiedName(nil)
 
        case _Lparen:
                p.next()
@@ -1233,6 +1284,27 @@ func (p *parser) typeOrNil() Expr {
        return nil
 }
 
+func (p *parser) typeInstance(typ Expr) Expr {
+       if trace {
+               defer p.trace("typeInstance")()
+       }
+
+       pos := p.pos()
+       p.want(_Lbrack)
+       if p.tok == _Rbrack {
+               p.error("expecting type")
+               p.next()
+               return typ
+       }
+
+       x := new(IndexExpr)
+       x.pos = pos
+       x.X = typ
+       x.Index, _ = p.typeList()
+       p.want(_Rbrack)
+       return x
+}
+
 func (p *parser) funcType() *FuncType {
        if trace {
                defer p.trace("funcType")()
@@ -1240,12 +1312,41 @@ func (p *parser) funcType() *FuncType {
 
        typ := new(FuncType)
        typ.pos = p.pos()
-       typ.ParamList = p.paramList()
+       p.want(_Lparen)
+       typ.ParamList = p.paramList(nil, _Rparen, false)
        typ.ResultList = p.funcResult()
 
        return typ
 }
 
+// "[" has already been consumed, and pos is its position.
+// If len != nil it is the already consumed array length.
+func (p *parser) arrayType(pos Pos, len Expr) Expr {
+       if trace {
+               defer p.trace("arrayType")()
+       }
+
+       if len == nil && !p.got(_DotDotDot) {
+               p.xnest++
+               len = p.expr()
+               p.xnest--
+       }
+       p.want(_Rbrack)
+       t := new(ArrayType)
+       t.pos = pos
+       t.Len = len
+       t.Elem = p.type_()
+       return t
+}
+
+// "[" and "]" have already been consumed, and pos is the position of "[".
+func (p *parser) sliceType(pos Pos) Expr {
+       t := new(SliceType)
+       t.pos = pos
+       t.Elem = p.type_()
+       return t
+}
+
 func (p *parser) chanElem() Expr {
        if trace {
                defer p.trace("chanElem")()
@@ -1261,22 +1362,6 @@ func (p *parser) chanElem() Expr {
        return typ
 }
 
-func (p *parser) dotname(name *Name) Expr {
-       if trace {
-               defer p.trace("dotname")()
-       }
-
-       if p.tok == _Dot {
-               s := new(SelectorExpr)
-               s.pos = p.pos()
-               p.next()
-               s.X = name
-               s.Sel = p.name()
-               return s
-       }
-       return name
-}
-
 // StructType = "struct" "{" { FieldDecl ";" } "}" .
 func (p *parser) structType() *StructType {
        if trace {
@@ -1287,7 +1372,8 @@ func (p *parser) structType() *StructType {
        typ.pos = p.pos()
 
        p.want(_Struct)
-       p.list(_Lbrace, _Semi, _Rbrace, func() bool {
+       p.want(_Lbrace)
+       p.list(_Semi, _Rbrace, func() bool {
                p.fieldDecl(typ)
                return false
        })
@@ -1305,9 +1391,54 @@ func (p *parser) interfaceType() *InterfaceType {
        typ.pos = p.pos()
 
        p.want(_Interface)
-       p.list(_Lbrace, _Semi, _Rbrace, func() bool {
-               if m := p.methodDecl(); m != nil {
-                       typ.MethodList = append(typ.MethodList, m)
+       p.want(_Lbrace)
+       p.list(_Semi, _Rbrace, func() bool {
+               switch p.tok {
+               case _Name:
+                       typ.MethodList = append(typ.MethodList, p.methodDecl())
+
+               case _Lparen:
+                       p.syntaxError("cannot parenthesize embedded type")
+                       f := new(Field)
+                       f.pos = p.pos()
+                       p.next()
+                       f.Type = p.qualifiedName(nil)
+                       p.want(_Rparen)
+                       typ.MethodList = append(typ.MethodList, f)
+
+               case _Type:
+                       if p.mode&AllowGenerics != 0 {
+                               // TODO(gri) factor this better
+                               type_ := NewName(p.pos(), "type") // cannot have a method named "type"
+                               p.next()
+                               if p.tok != _Semi && p.tok != _Rbrace {
+                                       f := new(Field)
+                                       f.pos = p.pos()
+                                       f.Name = type_
+                                       f.Type = p.type_()
+                                       typ.MethodList = append(typ.MethodList, f)
+                                       for p.got(_Comma) {
+                                               f := new(Field)
+                                               f.pos = p.pos()
+                                               f.Name = type_
+                                               f.Type = p.type_()
+                                               typ.MethodList = append(typ.MethodList, f)
+                                       }
+                               } else {
+                                       p.syntaxError("expecting type")
+                               }
+                               break
+                       }
+                       fallthrough
+
+               default:
+                       if p.mode&AllowGenerics != 0 {
+                               p.syntaxError("expecting method, interface name, or type list")
+                               p.advance(_Semi, _Rbrace, _Type)
+                       } else {
+                               p.syntaxError("expecting method or interface name")
+                               p.advance(_Semi, _Rbrace)
+                       }
                }
                return false
        })
@@ -1321,8 +1452,8 @@ func (p *parser) funcResult() []*Field {
                defer p.trace("funcResult")()
        }
 
-       if p.tok == _Lparen {
-               return p.paramList()
+       if p.got(_Lparen) {
+               return p.paramList(nil, _Rparen, false)
        }
 
        pos := p.pos()
@@ -1368,59 +1499,71 @@ func (p *parser) fieldDecl(styp *StructType) {
        case _Name:
                name := p.name()
                if p.tok == _Dot || p.tok == _Literal || p.tok == _Semi || p.tok == _Rbrace {
-                       // embed oliteral
+                       // embedded type
                        typ := p.qualifiedName(name)
                        tag := p.oliteral()
                        p.addField(styp, pos, nil, typ, tag)
-                       return
+                       break
                }
 
-               // new_name_list ntype oliteral
+               // name1, name2, ... Type [ tag ]
                names := p.nameList(name)
-               typ := p.type_()
+               var typ Expr
+
+               // Careful dance: We don't know if we have an embedded instantiated
+               // type T[P1, P2, ...] or a field T of array/slice type [P]E or []E.
+               if p.mode&AllowGenerics != 0 && len(names) == 1 && p.tok == _Lbrack {
+                       typ = p.arrayOrTArgs()
+                       if typ, ok := typ.(*IndexExpr); ok {
+                               // embedded type T[P1, P2, ...]
+                               typ.X = name // name == names[0]
+                               tag := p.oliteral()
+                               p.addField(styp, pos, nil, typ, tag)
+                               break
+                       }
+               } else {
+                       // T P
+                       typ = p.type_()
+               }
+
                tag := p.oliteral()
 
                for _, name := range names {
                        p.addField(styp, name.Pos(), name, typ, tag)
                }
 
-       case _Lparen:
+       case _Star:
                p.next()
-               if p.tok == _Star {
-                       // '(' '*' embed ')' oliteral
-                       pos := p.pos()
-                       p.next()
-                       typ := newIndirect(pos, p.qualifiedName(nil))
-                       p.want(_Rparen)
-                       tag := p.oliteral()
-                       p.addField(styp, pos, nil, typ, tag)
+               var typ Expr
+               if p.tok == _Lparen {
+                       // *(T)
                        p.syntaxError("cannot parenthesize embedded type")
-
+                       p.next()
+                       typ = p.qualifiedName(nil)
+                       p.got(_Rparen) // no need to complain if missing
                } else {
-                       // '(' embed ')' oliteral
-                       typ := p.qualifiedName(nil)
-                       p.want(_Rparen)
-                       tag := p.oliteral()
-                       p.addField(styp, pos, nil, typ, tag)
-                       p.syntaxError("cannot parenthesize embedded type")
+                       // *T
+                       typ = p.qualifiedName(nil)
                }
+               tag := p.oliteral()
+               p.addField(styp, pos, nil, newIndirect(pos, typ), tag)
 
-       case _Star:
+       case _Lparen:
+               p.syntaxError("cannot parenthesize embedded type")
                p.next()
-               if p.got(_Lparen) {
-                       // '*' '(' embed ')' oliteral
-                       typ := newIndirect(pos, p.qualifiedName(nil))
-                       p.want(_Rparen)
-                       tag := p.oliteral()
-                       p.addField(styp, pos, nil, typ, tag)
-                       p.syntaxError("cannot parenthesize embedded type")
-
+               var typ Expr
+               if p.tok == _Star {
+                       // (*T)
+                       pos := p.pos()
+                       p.next()
+                       typ = newIndirect(pos, p.qualifiedName(nil))
                } else {
-                       // '*' embed oliteral
-                       typ := newIndirect(pos, p.qualifiedName(nil))
-                       tag := p.oliteral()
-                       p.addField(styp, pos, nil, typ, tag)
+                       // (T)
+                       typ = p.qualifiedName(nil)
                }
+               p.got(_Rparen) // no need to complain if missing
+               tag := p.oliteral()
+               p.addField(styp, pos, nil, typ, tag)
 
        default:
                p.syntaxError("expecting field name or embedded type")
@@ -1428,6 +1571,39 @@ func (p *parser) fieldDecl(styp *StructType) {
        }
 }
 
+func (p *parser) arrayOrTArgs() Expr {
+       if trace {
+               defer p.trace("arrayOrTArgs")()
+       }
+
+       pos := p.pos()
+       p.want(_Lbrack)
+       if p.got(_Rbrack) {
+               return p.sliceType(pos)
+       }
+
+       // x [n]E or x[n,], x[n1, n2], ...
+       n, comma := p.typeList()
+       p.want(_Rbrack)
+       if !comma {
+               if elem := p.typeOrNil(); elem != nil {
+                       // x [n]E
+                       t := new(ArrayType)
+                       t.pos = pos
+                       t.Len = n
+                       t.Elem = elem
+                       return t
+               }
+       }
+
+       // x[n,], x[n1, n2], ...
+       t := new(IndexExpr)
+       t.pos = pos
+       // t.X will be filled in by caller
+       t.Index = n
+       return t
+}
+
 func (p *parser) oliteral() *BasicLit {
        if p.tok == _Literal {
                b := new(BasicLit)
@@ -1449,51 +1625,115 @@ func (p *parser) methodDecl() *Field {
                defer p.trace("methodDecl")()
        }
 
-       switch p.tok {
-       case _Name:
-               name := p.name()
-
-               // accept potential name list but complain
-               hasNameList := false
-               for p.got(_Comma) {
-                       p.name()
-                       hasNameList = true
-               }
-               if hasNameList {
-                       p.syntaxError("name list not allowed in interface type")
-                       // already progressed, no need to advance
-               }
+       f := new(Field)
+       f.pos = p.pos()
+       name := p.name()
 
-               f := new(Field)
-               f.pos = name.Pos()
-               if p.tok != _Lparen {
-                       // packname
-                       f.Type = p.qualifiedName(name)
-                       return f
-               }
+       // accept potential name list but complain
+       // TODO(gri) We probably don't need this special check anymore.
+       //           Nobody writes this kind of code. It's from ancient
+       //           Go beginnings.
+       hasNameList := false
+       for p.got(_Comma) {
+               p.name()
+               hasNameList = true
+       }
+       if hasNameList {
+               p.syntaxError("name list not allowed in interface type")
+               // already progressed, no need to advance
+       }
 
+       switch p.tok {
+       case _Lparen:
+               // method
                f.Name = name
                f.Type = p.funcType()
-               return f
 
-       case _Lparen:
-               p.syntaxError("cannot parenthesize embedded type")
-               f := new(Field)
-               f.pos = p.pos()
-               p.next()
-               f.Type = p.qualifiedName(nil)
-               p.want(_Rparen)
-               return f
+       case _Lbrack:
+               if p.mode&AllowGenerics != 0 {
+                       // Careful dance: We don't know if we have a generic method m[T C](x T)
+                       // or an embedded instantiated type T[P1, P2] (we accept generic methods
+                       // for generality and robustness of parsing).
+                       pos := p.pos()
+                       p.next()
+
+                       // Empty type parameter or argument lists are not permitted.
+                       // Treat as if [] were absent.
+                       if p.tok == _Rbrack {
+                               // name[]
+                               pos := p.pos()
+                               p.next()
+                               if p.tok == _Lparen {
+                                       // name[](
+                                       p.errorAt(pos, "empty type parameter list")
+                                       f.Name = name
+                                       f.Type = p.funcType()
+                               } else {
+                                       p.errorAt(pos, "empty type argument list")
+                                       f.Type = name
+                               }
+                               break
+                       }
+
+                       // A type argument list looks like a parameter list with only
+                       // types. Parse a parameter list and decide afterwards.
+                       list := p.paramList(nil, _Rbrack, false)
+                       if len(list) == 0 {
+                               // The type parameter list is not [] but we got nothing
+                               // due to other errors (reported by paramList). Treat
+                               // as if [] were absent.
+                               if p.tok == _Lparen {
+                                       f.Name = name
+                                       f.Type = p.funcType()
+                               } else {
+                                       f.Type = name
+                               }
+                               break
+                       }
+
+                       // len(list) > 0
+                       if list[0].Name != nil {
+                               // generic method
+                               f.Name = name
+                               f.Type = p.funcType()
+                               // TODO(gri) Record list as type parameter list with f.Type
+                               //           if we want to type-check the generic method.
+                               //           For now, report an error so this is not a silent event.
+                               p.errorAt(pos, "interface method cannot have type parameters")
+                               break
+                       }
+
+                       // embedded instantiated type
+                       t := new(IndexExpr)
+                       t.pos = pos
+                       t.X = name
+                       if len(list) == 1 {
+                               t.Index = list[0].Type
+                       } else {
+                               // len(list) > 1
+                               l := new(ListExpr)
+                               l.pos = list[0].Pos()
+                               l.ElemList = make([]Expr, len(list))
+                               for i := range list {
+                                       l.ElemList[i] = list[i].Type
+                               }
+                               t.Index = l
+                       }
+                       f.Type = t
+                       break
+               }
+               fallthrough
 
        default:
-               p.syntaxError("expecting method or interface name")
-               p.advance(_Semi, _Rbrace)
-               return nil
+               // embedded type
+               f.Type = p.qualifiedName(name)
        }
+
+       return f
 }
 
 // ParameterDecl = [ IdentifierList ] [ "..." ] Type .
-func (p *parser) paramDeclOrNil() *Field {
+func (p *parser) paramDeclOrNil(name *Name) *Field {
        if trace {
                defer p.trace("paramDecl")()
        }
@@ -1501,73 +1741,68 @@ func (p *parser) paramDeclOrNil() *Field {
        f := new(Field)
        f.pos = p.pos()
 
-       switch p.tok {
-       case _Name:
-               f.Name = p.name()
-               switch p.tok {
-               case _Name, _Star, _Arrow, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen:
-                       // sym name_or_type
-                       f.Type = p.type_()
+       if p.tok == _Name || name != nil {
+               if name == nil {
+                       name = p.name()
+               }
 
-               case _DotDotDot:
-                       // sym dotdotdot
-                       f.Type = p.dotsType()
+               if p.mode&AllowGenerics != 0 && p.tok == _Lbrack {
+                       f.Type = p.arrayOrTArgs()
+                       if typ, ok := f.Type.(*IndexExpr); ok {
+                               typ.X = name
+                       } else {
+                               f.Name = name
+                       }
+                       return f
+               }
 
-               case _Dot:
+               if p.tok == _Dot {
                        // name_or_type
-                       // from dotname
-                       f.Type = p.dotname(f.Name)
-                       f.Name = nil
+                       f.Type = p.qualifiedName(name)
+                       return f
                }
 
-       case _Arrow, _Star, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen:
-               // name_or_type
-               f.Type = p.type_()
-
-       case _DotDotDot:
-               // dotdotdot
-               f.Type = p.dotsType()
-
-       default:
-               p.syntaxError("expecting )")
-               p.advance(_Comma, _Rparen)
-               return nil
+               f.Name = name
        }
 
-       return f
-}
-
-// ...Type
-func (p *parser) dotsType() *DotsType {
-       if trace {
-               defer p.trace("dotsType")()
+       if p.tok == _DotDotDot {
+               t := new(DotsType)
+               t.pos = p.pos()
+               p.next()
+               t.Elem = p.typeOrNil()
+               if t.Elem == nil {
+                       t.Elem = p.badExpr()
+                       p.syntaxError("final argument in variadic function missing type")
+               }
+               f.Type = t
+               return f
        }
 
-       t := new(DotsType)
-       t.pos = p.pos()
-
-       p.want(_DotDotDot)
-       t.Elem = p.typeOrNil()
-       if t.Elem == nil {
-               t.Elem = p.badExpr()
-               p.syntaxError("final argument in variadic function missing type")
+       f.Type = p.typeOrNil()
+       if f.Name != nil || f.Type != nil {
+               return f
        }
 
-       return t
+       p.syntaxError("expecting )")
+       p.advance(_Comma, _Rparen)
+       return nil
 }
 
 // Parameters    = "(" [ ParameterList [ "," ] ] ")" .
 // ParameterList = ParameterDecl { "," ParameterDecl } .
-func (p *parser) paramList() (list []*Field) {
+// "(" or "[" has already been consumed.
+// If name != nil, it is the first name after "(" or "[".
+// In the result list, either all fields have a name, or no field has a name.
+func (p *parser) paramList(name *Name, close token, requireNames bool) (list []*Field) {
        if trace {
                defer p.trace("paramList")()
        }
 
-       pos := p.pos()
-
-       var named int // number of parameters that have an explicit name and type
-       p.list(_Lparen, _Comma, _Rparen, func() bool {
-               if par := p.paramDeclOrNil(); par != nil {
+       var named int // number of parameters that have an explicit name and type/bound
+       p.list(_Comma, close, func() bool {
+               par := p.paramDeclOrNil(name)
+               name = nil // 1st name was consumed if present
+               if par != nil {
                        if debug && par.Name == nil && par.Type == nil {
                                panic("parameter without name or type")
                        }
@@ -1579,7 +1814,11 @@ func (p *parser) paramList() (list []*Field) {
                return false
        })
 
-       // distribute parameter types
+       if len(list) == 0 {
+               return
+       }
+
+       // distribute parameter types (len(list) > 0)
        if named == 0 {
                // all unnamed => found names are named types
                for _, par := range list {
@@ -1588,31 +1827,38 @@ func (p *parser) paramList() (list []*Field) {
                                par.Name = nil
                        }
                }
+               if requireNames {
+                       p.syntaxErrorAt(list[0].Type.Pos(), "type parameters must be named")
+               }
        } else if named != len(list) {
-               // some named => all must be named
-               ok := true
+               // some named => all must have names and types
+               var pos Pos // left-most error position (or unknown)
                var typ Expr
                for i := len(list) - 1; i >= 0; i-- {
                        if par := list[i]; par.Type != nil {
                                typ = par.Type
                                if par.Name == nil {
-                                       ok = false
-                                       n := p.newName("_")
-                                       n.pos = typ.Pos() // correct position
-                                       par.Name = n
+                                       pos = typ.Pos()
+                                       par.Name = NewName(pos, "_")
                                }
                        } else if typ != nil {
                                par.Type = typ
                        } else {
                                // par.Type == nil && typ == nil => we only have a par.Name
-                               ok = false
+                               pos = par.Name.Pos()
                                t := p.badExpr()
-                               t.pos = par.Name.Pos() // correct position
+                               t.pos = pos // correct position
                                par.Type = t
                        }
                }
-               if !ok {
-                       p.syntaxErrorAt(pos, "mixed named and unnamed function parameters")
+               if pos.IsKnown() {
+                       var msg string
+                       if requireNames {
+                               msg = "type parameters must be named"
+                       } else {
+                               msg = "mixed named and unnamed parameters"
+                       }
+                       p.syntaxErrorAt(pos, msg)
                }
        }
 
@@ -2208,14 +2454,18 @@ func (p *parser) stmtList() (l []Stmt) {
        return
 }
 
-// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
+// argList parses a possibly empty, comma-separated list of arguments,
+// optionally followed by a comma (if not empty), and closed by ")".
+// The last argument may be followed by "...".
+//
+// argList = [ arg { "," arg } [ "..." ] [ "," ] ] ")" .
 func (p *parser) argList() (list []Expr, hasDots bool) {
        if trace {
                defer p.trace("argList")()
        }
 
        p.xnest++
-       p.list(_Lparen, _Comma, _Rparen, func() bool {
+       p.list(_Comma, _Rparen, func() bool {
                list = append(list, p.expr())
                hasDots = p.got(_DotDotDot)
                return hasDots
@@ -2228,23 +2478,16 @@ func (p *parser) argList() (list []Expr, hasDots bool) {
 // ----------------------------------------------------------------------------
 // Common productions
 
-func (p *parser) newName(value string) *Name {
-       n := new(Name)
-       n.pos = p.pos()
-       n.Value = value
-       return n
-}
-
 func (p *parser) name() *Name {
        // no tracing to avoid overly verbose output
 
        if p.tok == _Name {
-               n := p.newName(p.lit)
+               n := NewName(p.pos(), p.lit)
                p.next()
                return n
        }
 
-       n := p.newName("_")
+       n := NewName(p.pos(), "_")
        p.syntaxError("expecting name")
        p.advance()
        return n
@@ -2275,18 +2518,32 @@ func (p *parser) qualifiedName(name *Name) Expr {
                defer p.trace("qualifiedName")()
        }
 
+       var x Expr
        switch {
        case name != nil:
-               // name is provided
+               x = name
        case p.tok == _Name:
-               name = p.name()
+               x = p.name()
        default:
-               name = p.newName("_")
+               x = NewName(p.pos(), "_")
                p.syntaxError("expecting name")
                p.advance(_Dot, _Semi, _Rbrace)
        }
 
-       return p.dotname(name)
+       if p.tok == _Dot {
+               s := new(SelectorExpr)
+               s.pos = p.pos()
+               p.next()
+               s.X = x
+               s.Sel = p.name()
+               x = s
+       }
+
+       if p.mode&AllowGenerics != 0 && p.tok == _Lbrack {
+               x = p.typeInstance(x)
+       }
+
+       return x
 }
 
 // ExpressionList = Expression { "," Expression } .
@@ -2309,6 +2566,41 @@ func (p *parser) exprList() Expr {
        return x
 }
 
+// typeList parses a non-empty, comma-separated list of expressions,
+// optionally followed by a comma. The first list element may be any
+// expression, all other list elements must be type expressions.
+// If there is more than one argument, the result is a *ListExpr.
+// The comma result indicates whether there was a (separating or
+// trailing) comma.
+//
+// typeList = arg { "," arg } [ "," ] .
+func (p *parser) typeList() (x Expr, comma bool) {
+       if trace {
+               defer p.trace("typeList")()
+       }
+
+       p.xnest++
+       x = p.expr()
+       if p.got(_Comma) {
+               comma = true
+               if t := p.typeOrNil(); t != nil {
+                       list := []Expr{x, t}
+                       for p.got(_Comma) {
+                               if t = p.typeOrNil(); t == nil {
+                                       break
+                               }
+                               list = append(list, t)
+                       }
+                       l := new(ListExpr)
+                       l.pos = x.Pos() // == list[0].Pos()
+                       l.ElemList = list
+                       x = l
+               }
+       }
+       p.xnest--
+       return
+}
+
 // unparen removes all parentheses around an expression.
 func unparen(x Expr) Expr {
        for {
index 81945faee95e2d55ac2dfca3f7ffdd2e5901d552..ea9e9acc83c2e512e5c0ea7e23cd525ed1836c26 100644 (file)
@@ -26,10 +26,35 @@ var (
 )
 
 func TestParse(t *testing.T) {
-       ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0)
+       ParseFile(*src_, func(err error) { t.Error(err) }, nil, AllowGenerics)
 }
 
-func TestStdLib(t *testing.T) {
+func TestVerify(t *testing.T) {
+       ast, err := ParseFile(*src_, func(err error) { t.Error(err) }, nil, AllowGenerics)
+       if err != nil {
+               return // error already reported
+       }
+       verifyPrint(t, *src_, ast)
+}
+
+func TestParseGo2(t *testing.T) {
+       dir := filepath.Join(testdata, "go2")
+       list, err := ioutil.ReadDir(dir)
+       if err != nil {
+               t.Fatal(err)
+       }
+       for _, fi := range list {
+               name := fi.Name()
+               if !fi.IsDir() && !strings.HasPrefix(name, ".") {
+                       ParseFile(filepath.Join(dir, name), func(err error) { t.Error(err) }, nil, AllowGenerics)
+               }
+       }
+}
+
+func TestStdLib(t *testing.T)        { testStdLib(t, 0) }
+func TestStdLibGeneric(t *testing.T) { testStdLib(t, AllowGenerics) }
+
+func testStdLib(t *testing.T, mode Mode) {
        if testing.Short() {
                t.Skip("skipping test in short mode")
        }
@@ -68,15 +93,15 @@ func TestStdLib(t *testing.T) {
                                if debug {
                                        fmt.Printf("parsing %s\n", filename)
                                }
-                               ast, err := ParseFile(filename, nil, nil, 0)
+                               ast, err := ParseFile(filename, nil, nil, mode)
                                if err != nil {
                                        t.Error(err)
                                        return
                                }
                                if *verify {
-                                       verifyPrint(filename, ast)
+                                       verifyPrint(t, filename, ast)
                                }
-                               results <- parseResult{filename, ast.Lines}
+                               results <- parseResult{filename, ast.EOF.Line()}
                        })
                }
        }()
@@ -142,12 +167,13 @@ func walkDirs(t *testing.T, dir string, action func(string)) {
        }
 }
 
-func verifyPrint(filename string, ast1 *File) {
+func verifyPrint(t *testing.T, filename string, ast1 *File) {
        var buf1 bytes.Buffer
        _, err := Fprint(&buf1, ast1, true)
        if err != nil {
                panic(err)
        }
+       bytes1 := buf1.Bytes()
 
        ast2, err := Parse(NewFileBase(filename), &buf1, nil, nil, 0)
        if err != nil {
@@ -159,16 +185,18 @@ func verifyPrint(filename string, ast1 *File) {
        if err != nil {
                panic(err)
        }
+       bytes2 := buf2.Bytes()
 
-       if bytes.Compare(buf1.Bytes(), buf2.Bytes()) != 0 {
+       if bytes.Compare(bytes1, bytes2) != 0 {
                fmt.Printf("--- %s ---\n", filename)
-               fmt.Printf("%s\n", buf1.Bytes())
+               fmt.Printf("%s\n", bytes1)
                fmt.Println()
 
                fmt.Printf("--- %s ---\n", filename)
-               fmt.Printf("%s\n", buf2.Bytes())
+               fmt.Printf("%s\n", bytes2)
                fmt.Println()
-               panic("not equal")
+
+               t.Error("printed syntax trees do not match")
        }
 }
 
index c683c7fcfc1fbde013bb5f14f5220c2ac1cca9af..99734d42d801f7271af8e67065e13c19998ff20d 100644 (file)
@@ -26,6 +26,7 @@ func MakePos(base *PosBase, line, col uint) Pos { return Pos{base, sat32(line),
 // TODO(gri) IsKnown makes an assumption about linebase < 1.
 //           Maybe we should check for Base() != nil instead.
 
+func (pos Pos) Pos() Pos       { return pos }
 func (pos Pos) IsKnown() bool  { return pos.line > 0 }
 func (pos Pos) Base() *PosBase { return pos.base }
 func (pos Pos) Line() uint     { return uint(pos.line) }
index 8ff3bfa79443523e9009e23cbe95ce3647088965..c8bf59675a2fedb8291580842e005275ba3d9400 100644 (file)
@@ -484,7 +484,15 @@ func (p *printer) printRawNode(n Node) {
                if n.Dir == SendOnly {
                        p.print(_Arrow)
                }
-               p.print(blank, n.Elem)
+               p.print(blank)
+               if e, _ := n.Elem.(*ChanType); n.Dir == 0 && e != nil && e.Dir == RecvOnly {
+                       // don't print chan (<-chan T) as chan <-chan T
+                       p.print(_Lparen)
+                       p.print(n.Elem)
+                       p.print(_Rparen)
+               } else {
+                       p.print(n.Elem)
+               }
 
        // statements
        case *DeclStmt:
index fe72e7a374fb8dc8701de5093b0a58d0e4ffb3d1..9f1f7e18cbf1f4bf6735a1762de381f50df51c66 100644 (file)
@@ -30,12 +30,28 @@ func TestPrint(t *testing.T) {
        }
 }
 
+var stringTests = []string{
+       "package p",
+       "package p; type _ int; type T1 = struct{}; type ( _ *struct{}; T2 = float32 )",
+
+       // channels
+       "package p; type _ chan chan int",
+       "package p; type _ chan (<-chan int)",
+       "package p; type _ chan chan<- int",
+
+       "package p; type _ <-chan chan int",
+       "package p; type _ <-chan <-chan int",
+       "package p; type _ <-chan chan<- int",
+
+       "package p; type _ chan<- chan int",
+       "package p; type _ chan<- <-chan int",
+       "package p; type _ chan<- chan<- int",
+
+       // TODO(gri) expand
+}
+
 func TestPrintString(t *testing.T) {
-       for _, want := range []string{
-               "package p",
-               "package p; type _ = int; type T1 = struct{}; type ( _ = *struct{}; T2 = float32 )",
-               // TODO(gri) expand
-       } {
+       for _, want := range stringTests {
                ast, err := Parse(nil, strings.NewReader(want), nil, nil, 0)
                if err != nil {
                        t.Error(err)
index e51b5538b3b18221a111830519f12358528f6d7b..f3d4c09ed5e045fad13d469def95cb386b73cd6a 100644 (file)
@@ -16,6 +16,7 @@ type Mode uint
 // Modes supported by the parser.
 const (
        CheckBranches Mode = 1 << iota // check correct use of labels, break, continue, and goto statements
+       AllowGenerics
 )
 
 // Error describes a syntax error. Error implements the error interface.
diff --git a/src/cmd/compile/internal/syntax/testdata/go2/chans.go2 b/src/cmd/compile/internal/syntax/testdata/go2/chans.go2
new file mode 100644 (file)
index 0000000..fad2bce
--- /dev/null
@@ -0,0 +1,62 @@
+package chans
+
+import "runtime"
+
+// Ranger returns a Sender and a Receiver. The Receiver provides a
+// Next method to retrieve values. The Sender provides a Send method
+// to send values and a Close method to stop sending values. The Next
+// method indicates when the Sender has been closed, and the Send
+// method indicates when the Receiver has been freed.
+//
+// This is a convenient way to exit a goroutine sending values when
+// the receiver stops reading them.
+func Ranger[T any]() (*Sender[T], *Receiver[T]) {
+       c := make(chan T)
+       d := make(chan bool)
+       s := &Sender[T]{values: c, done: d}
+       r := &Receiver[T]{values: c, done: d}
+       runtime.SetFinalizer(r, r.finalize)
+       return s, r
+}
+
+// A sender is used to send values to a Receiver.
+type Sender[T any] struct {
+       values chan<- T
+       done <-chan bool
+}
+
+// Send sends a value to the receiver. It returns whether any more
+// values may be sent; if it returns false the value was not sent.
+func (s *Sender[T]) Send(v T) bool {
+       select {
+       case s.values <- v:
+               return true
+       case <-s.done:
+               return false
+       }
+}
+
+// Close tells the receiver that no more values will arrive.
+// After Close is called, the Sender may no longer be used.
+func (s *Sender[T]) Close() {
+       close(s.values)
+}
+
+// A Receiver receives values from a Sender.
+type Receiver[T any] struct {
+       values <-chan T
+       done chan<- bool
+}
+
+// Next returns the next value from the channel. The bool result
+// indicates whether the value is valid, or whether the Sender has
+// been closed and no more values will be received.
+func (r *Receiver[T]) Next() (T, bool) {
+       v, ok := <-r.values
+       return v, ok
+}
+
+// finalize is a finalizer for the receiver.
+func (r *Receiver[T]) finalize() {
+       close(r.done)
+}
diff --git a/src/cmd/compile/internal/syntax/testdata/go2/linalg.go2 b/src/cmd/compile/internal/syntax/testdata/go2/linalg.go2
new file mode 100644 (file)
index 0000000..0d27603
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright 2019 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 linalg
+
+import "math"
+
+// Numeric is type bound that matches any numeric type.
+// It would likely be in a constraints package in the standard library.
+type Numeric interface {
+       type int, int8, int16, int32, int64,
+               uint, uint8, uint16, uint32, uint64, uintptr,
+               float32, float64,
+               complex64, complex128
+}
+
+func DotProduct[T Numeric](s1, s2 []T) T {
+       if len(s1) != len(s2) {
+               panic("DotProduct: slices of unequal length")
+       }
+       var r T
+       for i := range s1 {
+               r += s1[i] * s2[i]
+       }
+       return r
+}
+
+// NumericAbs matches numeric types with an Abs method.
+type NumericAbs[T any] interface {
+       Numeric
+
+       Abs() T
+}
+
+// AbsDifference computes the absolute value of the difference of
+// a and b, where the absolute value is determined by the Abs method.
+func AbsDifference[T NumericAbs[T]](a, b T) T {
+       d := a - b
+       return d.Abs()
+}
+
+// OrderedNumeric is a type bound that matches numeric types that support the < operator.
+type OrderedNumeric interface {
+       type int, int8, int16, int32, int64,
+               uint, uint8, uint16, uint32, uint64, uintptr,
+               float32, float64
+}
+
+// Complex is a type bound that matches the two complex types, which do not have a < operator.
+type Complex interface {
+       type complex64, complex128
+}
+
+// OrderedAbs is a helper type that defines an Abs method for
+// ordered numeric types.
+type OrderedAbs[T OrderedNumeric] T
+
+func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
+       if a < 0 {
+               return -a
+       }
+       return a
+}
+
+// ComplexAbs is a helper type that defines an Abs method for
+// complex types.
+type ComplexAbs[T Complex] T
+
+func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
+       r := float64(real(a))
+       i := float64(imag(a))
+       d := math.Sqrt(r * r + i * i)
+       return ComplexAbs[T](complex(d, 0))
+}
+
+func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
+       return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
+}
+
+func ComplexAbsDifference[T Complex](a, b T) T {
+       return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
+}
diff --git a/src/cmd/compile/internal/syntax/testdata/go2/map.go2 b/src/cmd/compile/internal/syntax/testdata/go2/map.go2
new file mode 100644 (file)
index 0000000..814d953
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2019 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 orderedmap provides an ordered map, implemented as a binary tree.
+package orderedmap
+
+// TODO(gri) fix imports for tests
+import "chans" // ERROR could not import
+
+// Map is an ordered map.
+type Map[K, V any] struct {
+       root    *node[K, V]
+       compare func(K, K) int
+}
+
+// node is the type of a node in the binary tree.
+type node[K, V any] struct {
+       key         K
+       val         V
+       left, right *node[K, V]
+}
+
+// New returns a new map.
+func New[K, V any](compare func(K, K) int) *Map[K, V] {
+        return &Map[K, V]{compare: compare}
+}
+
+// find looks up key in the map, and returns either a pointer
+// to the node holding key, or a pointer to the location where
+// such a node would go.
+func (m *Map[K, V]) find(key K) **node[K, V] {
+       pn := &m.root
+       for *pn != nil {
+               switch cmp := m.compare(key, (*pn).key); {
+               case cmp < 0:
+                       pn = &(*pn).left
+               case cmp > 0:
+                       pn = &(*pn).right
+               default:
+                       return pn
+               }
+       }
+       return pn
+}
+
+// Insert inserts a new key/value into the map.
+// If the key is already present, the value is replaced.
+// Returns true if this is a new key, false if already present.
+func (m *Map[K, V]) Insert(key K, val V) bool {
+       pn := m.find(key)
+       if *pn != nil {
+               (*pn).val = val
+               return false
+       }
+        *pn = &node[K, V]{key: key, val: val}
+       return true
+}
+
+// Find returns the value associated with a key, or zero if not present.
+// The found result reports whether the key was found.
+func (m *Map[K, V]) Find(key K) (V, bool) {
+       pn := m.find(key)
+       if *pn == nil {
+               var zero V // see the discussion of zero values, above
+               return zero, false
+       }
+       return (*pn).val, true
+}
+
+// keyValue is a pair of key and value used when iterating.
+type keyValue[K, V any] struct {
+       key K
+       val V
+}
+
+// InOrder returns an iterator that does an in-order traversal of the map.
+func (m *Map[K, V]) InOrder() *Iterator[K, V] {
+       sender, receiver := chans.Ranger[keyValue[K, V]]()
+       var f func(*node[K, V]) bool
+       f = func(n *node[K, V]) bool {
+               if n == nil {
+                       return true
+               }
+               // Stop sending values if sender.Send returns false,
+               // meaning that nothing is listening at the receiver end.
+               return f(n.left) &&
+                        sender.Send(keyValue[K, V]{n.key, n.val}) &&
+                       f(n.right)
+       }
+       go func() {
+               f(m.root)
+               sender.Close()
+       }()
+       return &Iterator[K, V]{receiver}
+}
+
+// Iterator is used to iterate over the map.
+type Iterator[K, V any] struct {
+       r *chans.Receiver[keyValue[K, V]]
+}
+
+// Next returns the next key and value pair, and a boolean indicating
+// whether they are valid or whether we have reached the end.
+func (it *Iterator[K, V]) Next() (K, V, bool) {
+       keyval, ok := it.r.Next()
+       if !ok {
+               var zerok K
+               var zerov V
+               return zerok, zerov, false
+       }
+       return keyval.key, keyval.val, true
+}
diff --git a/src/cmd/compile/internal/syntax/testdata/go2/map2.go2 b/src/cmd/compile/internal/syntax/testdata/go2/map2.go2
new file mode 100644 (file)
index 0000000..2833445
--- /dev/null
@@ -0,0 +1,146 @@
+// Copyright 2019 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.
+
+// This file is like map.go2, but instead if importing chans, it contains
+// the necessary functionality at the end of the file.
+
+// Package orderedmap provides an ordered map, implemented as a binary tree.
+package orderedmap
+
+// Map is an ordered map.
+type Map[K, V any] struct {
+       root    *node[K, V]
+       compare func(K, K) int
+}
+
+// node is the type of a node in the binary tree.
+type node[K, V any] struct {
+       key         K
+       val         V
+       left, right *node[K, V]
+}
+
+// New returns a new map.
+func New[K, V any](compare func(K, K) int) *Map[K, V] {
+        return &Map[K, V]{compare: compare}
+}
+
+// find looks up key in the map, and returns either a pointer
+// to the node holding key, or a pointer to the location where
+// such a node would go.
+func (m *Map[K, V]) find(key K) **node[K, V] {
+       pn := &m.root
+       for *pn != nil {
+               switch cmp := m.compare(key, (*pn).key); {
+               case cmp < 0:
+                       pn = &(*pn).left
+               case cmp > 0:
+                       pn = &(*pn).right
+               default:
+                       return pn
+               }
+       }
+       return pn
+}
+
+// Insert inserts a new key/value into the map.
+// If the key is already present, the value is replaced.
+// Returns true if this is a new key, false if already present.
+func (m *Map[K, V]) Insert(key K, val V) bool {
+       pn := m.find(key)
+       if *pn != nil {
+               (*pn).val = val
+               return false
+       }
+       *pn = &node[K, V]{key: key, val: val}
+       return true
+}
+
+// Find returns the value associated with a key, or zero if not present.
+// The found result reports whether the key was found.
+func (m *Map[K, V]) Find(key K) (V, bool) {
+       pn := m.find(key)
+       if *pn == nil {
+               var zero V // see the discussion of zero values, above
+               return zero, false
+       }
+       return (*pn).val, true
+}
+
+// keyValue is a pair of key and value used when iterating.
+type keyValue[K, V any] struct {
+       key K
+       val V
+}
+
+// InOrder returns an iterator that does an in-order traversal of the map.
+func (m *Map[K, V]) InOrder() *Iterator[K, V] {
+       sender, receiver := chans_Ranger[keyValue[K, V]]()
+       var f func(*node[K, V]) bool
+       f = func(n *node[K, V]) bool {
+               if n == nil {
+                       return true
+               }
+               // Stop sending values if sender.Send returns false,
+               // meaning that nothing is listening at the receiver end.
+               return f(n.left) &&
+                        sender.Send(keyValue[K, V]{n.key, n.val}) &&
+                       f(n.right)
+       }
+       go func() {
+               f(m.root)
+               sender.Close()
+       }()
+       return &Iterator[K, V]{receiver}
+}
+
+// Iterator is used to iterate over the map.
+type Iterator[K, V any] struct {
+       r *chans_Receiver[keyValue[K, V]]
+}
+
+// Next returns the next key and value pair, and a boolean indicating
+// whether they are valid or whether we have reached the end.
+func (it *Iterator[K, V]) Next() (K, V, bool) {
+       keyval, ok := it.r.Next()
+       if !ok {
+               var zerok K
+               var zerov V
+               return zerok, zerov, false
+       }
+       return keyval.key, keyval.val, true
+}
+
+// chans
+
+func chans_Ranger[T any]() (*chans_Sender[T], *chans_Receiver[T])
+
+// A sender is used to send values to a Receiver.
+type chans_Sender[T any] struct {
+       values chan<- T
+       done <-chan bool
+}
+
+func (s *chans_Sender[T]) Send(v T) bool {
+       select {
+       case s.values <- v:
+               return true
+       case <-s.done:
+               return false
+       }
+}
+
+func (s *chans_Sender[T]) Close() {
+       close(s.values)
+}
+
+type chans_Receiver[T any] struct {
+       values <-chan T
+       done chan<- bool
+}
+
+func (r *chans_Receiver[T]) Next() (T, bool) {
+       v, ok := <-r.values
+       return v, ok
+}
\ No newline at end of file
diff --git a/src/cmd/compile/internal/syntax/testdata/go2/slices.go2 b/src/cmd/compile/internal/syntax/testdata/go2/slices.go2
new file mode 100644 (file)
index 0000000..2bacd1c
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2019 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 slices implements various slice algorithms.
+package slices
+
+// Map turns a []T1 to a []T2 using a mapping function.
+func Map[T1, T2 any](s []T1, f func(T1) T2) []T2 {
+       r := make([]T2, len(s))
+       for i, v := range s {
+               r[i] = f(v)
+       }
+       return r
+}
+
+// Reduce reduces a []T1 to a single value using a reduction function.
+func Reduce[T1, T2 any](s []T1, initializer T2, f func(T2, T1) T2) T2 {
+       r := initializer
+       for _, v := range s {
+               r = f(r, v)
+       }
+       return r
+}
+
+// Filter filters values from a slice using a filter function.
+func Filter[T any](s []T, f func(T) bool) []T {
+       var r []T
+       for _, v := range s {
+               if f(v) {
+                       r = append(r, v)
+               }
+       }
+       return r
+}
+
+// Example uses
+
+func limiter(x int) byte {
+       switch {
+       case x < 0:
+               return 0
+       default:
+               return byte(x)
+       case x > 255:
+               return 255
+       }
+}
+
+var input = []int{-4, 68954, 7, 44, 0, -555, 6945}
+var limited1 = Map[int, byte](input, limiter)
+var limited2 = Map(input, limiter) // using type inference
+
+func reducer(x float64, y int) float64 {
+       return x + float64(y)
+}
+
+var reduced1 = Reduce[int, float64](input, 0, reducer)
+var reduced2 = Reduce(input, 1i /* ERROR overflows */, reducer) // using type inference
+var reduced3 = Reduce(input, 1, reducer) // using type inference
+
+func filter(x int) bool {
+       return x&1 != 0
+}
+
+var filtered1 = Filter[int](input, filter)
+var filtered2 = Filter(input, filter) // using type inference
+
diff --git a/src/cmd/compile/internal/syntax/testdata/go2/smoketest.go2 b/src/cmd/compile/internal/syntax/testdata/go2/smoketest.go2
new file mode 100644 (file)
index 0000000..e5cfba0
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright 2020 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.
+
+// This file contains basic generic code snippets.
+
+package p
+
+// type parameter lists
+type B[P any] struct{}
+type _[P interface{}] struct{}
+type _[P B] struct{}
+type _[P B[P]] struct{}
+
+type _[A, B, C any] struct{}
+type _[A, B, C B] struct{}
+type _[A, B, C B[A, B, C]] struct{}
+type _[A1, A2 B1, A3 B2, A4, A5, A6 B3] struct{}
+
+type _[A interface{}] struct{}
+type _[A, B interface{ m() }] struct{}
+
+type _[A, B, C any] struct{}
+
+// in functions
+func _[P any]()
+func _[P interface{}]()
+func _[P B]()
+func _[P B[P]]()
+
+// in methods
+func (T) _[P any]()
+func (T) _[P interface{}]()
+func (T) _[P B]()
+func (T) _[P B[P]]()
+
+// type instantiations
+type _ T[int]
+
+// in expressions
+var _ = T[int]{}
+
+// in embedded types
+type _ struct{ T[int] }
+
+// interfaces
+type _ interface{
+       m()
+       type int
+}
+
+type _ interface{
+       type int, float, string
+       type complex128
+       underlying(underlying underlying) underlying
+}
+
+type _ interface{
+       T
+       T[int]
+}
+
+// tricky cases
+func _(T[P], T[P1, P2])
+func _(a [N]T)
+
+type _ struct{
+       T[P]
+       T[P1, P2]
+       f [N]
+}
+type _ interface{
+       m()
+
+       // generic methods - disabled for now
+       // m[] /* ERROR empty type parameter list */ ()
+       // m[ /* ERROR cannot have type parameters */ P any](P)
+
+       // instantiated types
+       // T[] /* ERROR empty type argument list */ 
+       T[P]
+       T[P1, P2]
+}
diff --git a/src/cmd/compile/internal/syntax/testdata/go2/typeinst.go2 b/src/cmd/compile/internal/syntax/testdata/go2/typeinst.go2
new file mode 100644 (file)
index 0000000..a422d5e
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2019 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 myInt int
+
+// Parameterized type declarations
+
+type T1[P any] P
+
+type T2[P any] struct {
+        f P
+        g int // int should still be in scope chain
+}
+
+type List[P any] []P
+
+// Alias type declarations cannot have type parameters. Syntax error.
+// TODO(gri) Disabled for now as we don't check syntax error here.
+// type A1[P any] = /* ERROR cannot be alias */ P
+
+// But an alias may refer to a generic, uninstantiated type.
+type A2 = List
+var _ A2[int]
+var _ A2 /* ERROR without instantiation */
+
+type A3 = List[int]
+var _ A3
+
+// Parameterized type instantiations
+
+var x int
+type _ x /* ERROR not a type */ [int]
+
+type _ int /* ERROR not a generic type */ [int]
+type _ myInt /* ERROR not a generic type */ [int]
+
+// TODO(gri) better error messages
+type _ T1[int]
+type _ T1[x /* ERROR not a type */ ]
+type _ T1 /* ERROR got 2 arguments but 1 type parameters */ [int, float32]
+
+var _ T2[int] = T2[int]{}
+
+var _ List[int] = []int{1, 2, 3}
+var _ List[[]int] = [][]int{{1, 2, 3}}
+var _ List[List[List[int]]]
+
+// Parameterized types containing parameterized types
+
+type T3[P any] List[P]
+
+var _ T3[int] = T3[int](List[int]{1, 2, 3})
+
+// Self-recursive generic types are not permitted
+
+type self1[P any] self1 /* ERROR illegal cycle */ [P]
+type self2[P any] *self2[P] // this is ok
diff --git a/src/cmd/compile/internal/syntax/testdata/go2/typeinst2.go2 b/src/cmd/compile/internal/syntax/testdata/go2/typeinst2.go2
new file mode 100644 (file)
index 0000000..6e2104a
--- /dev/null
@@ -0,0 +1,256 @@
+// Copyright 2019 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 List[E any] []E
+var _ List[List[List[int]]]
+var _ List[List[List[int]]] = []List[List[int]]{}
+
+type (
+       T1[P1 any] struct {
+               f1 T2[P1, float32]
+       }
+
+       T2[P2, P3 any] struct {
+               f2 P2
+               f3 P3
+       }
+)
+
+func _() {
+       var x1 T1[int]
+       var x2 T2[int, float32]
+
+       x1.f1.f2 = 0
+       x1.f1 = x2
+}
+
+type T3[P any] T1[T2[P, P]]
+
+func _() {
+       var x1 T3[int]
+       var x2 T2[int, int]
+       x1.f1.f2 = x2
+}
+
+func f[P any] (x P) List[P] {
+       return List[P]{x}
+}
+
+var (
+       _ []int = f(0)
+       _ []float32 = f[float32](10)
+       _ List[complex128] = f(1i)
+       _ []List[int] = f(List[int]{})
+        _ List[List[int]] = []List[int]{}
+        _ = []List[int]{}
+)
+
+// Parameterized types with methods
+
+func (l List[E]) Head() (_ E, _ bool) {
+       if len(l) > 0 {
+               return l[0], true
+       }
+       return
+}
+
+// A test case for instantiating types with other types (extracted from map.go2)
+
+type Pair[K any] struct {
+       key K
+}
+
+type Receiver[T any] struct {
+       values T
+}
+
+type Iterator[K any] struct {
+       r Receiver[Pair[K]]
+}
+
+func Values [T any] (r Receiver[T]) T {
+        return r.values
+}
+
+func (it Iterator[K]) Next() K {
+        return Values[Pair[K]](it.r).key
+}
+
+// A more complex test case testing type bounds (extracted from linalg.go2 and reduced to essence)
+
+type NumericAbs[T any] interface {
+       Abs() T
+}
+
+func AbsDifference[T NumericAbs[T]](x T)
+
+type OrderedAbs[T any] T
+
+func (a OrderedAbs[T]) Abs() OrderedAbs[T]
+
+func OrderedAbsDifference[T any](x T) {
+       AbsDifference(OrderedAbs[T](x))
+}
+
+// same code, reduced to essence
+
+func g[P interface{ m() P }](x P)
+
+type T4[P any] P
+
+func (_ T4[P]) m() T4[P]
+
+func _[Q any](x Q) {
+       g(T4[Q](x))
+}
+
+// Another test case that caused  problems in the past
+
+type T5[_ interface { a() }, _ interface{}] struct{}
+
+type A[P any] struct{ x P }
+
+func (_ A[P]) a() {}
+
+var _ T5[A[int], int]
+
+// Invoking methods with parameterized receiver types uses
+// type inference to determine the actual type arguments matching
+// the receiver type parameters from the actual receiver argument.
+// Go does implicit address-taking and dereferenciation depending
+// on the actual receiver and the method's receiver type. To make
+// type inference work, the type-checker matches "pointer-ness"
+// of the actual receiver and the method's receiver type.
+// The following code tests this mechanism.
+
+type R1[A any] struct{}
+func (_ R1[A]) vm()
+func (_ *R1[A]) pm()
+
+func _[T any](r R1[T], p *R1[T]) {
+       r.vm()
+       r.pm()
+       p.vm()
+       p.pm()
+}
+
+type R2[A, B any] struct{}
+func (_ R2[A, B]) vm()
+func (_ *R2[A, B]) pm()
+
+func _[T any](r R2[T, int], p *R2[string, T]) {
+       r.vm()
+       r.pm()
+       p.vm()
+       p.pm()
+}
+
+// An interface can (explicitly) declare at most one type list.
+type _ interface {
+       m0()
+       type int, string, bool
+       type /* ERROR multiple type lists */ float32, float64
+       m1()
+       m2()
+       type /* ERROR multiple type lists */ complex64, complex128
+       type /* ERROR multiple type lists */ rune
+}
+
+// Interface type lists may contain each type at most once.
+// (If there are multiple lists, we assume the author intended
+// for them to be all in a single list, and we report the error
+// as well.)
+type _ interface {
+       type int, int /* ERROR duplicate type int */
+       type /* ERROR multiple type lists */ int /* ERROR duplicate type int */
+}
+
+type _ interface {
+       type struct{f int}, struct{g int}, struct /* ERROR duplicate type */ {f int}
+}
+
+// Interface type lists can contain any type, incl. *Named types.
+// Verify that we use the underlying type to compute the operational type.
+type MyInt int
+func add1[T interface{type MyInt}](x T) T {
+       return x + 1
+}
+
+type MyString string
+func double[T interface{type MyInt, MyString}](x T) T {
+       return x + x
+}
+
+// Embedding of interfaces with type lists leads to interfaces
+// with type lists that are the intersection of the embedded
+// type lists.
+
+type E0 interface {
+       type int, bool, string
+}
+
+type E1 interface {
+       type int, float64, string
+}
+
+type E2 interface {
+       type float64
+}
+
+type I0 interface {
+       E0
+}
+
+func f0[T I0]()
+var _ = f0[int]
+var _ = f0[bool]
+var _ = f0[string]
+var _ = f0[float64 /* ERROR does not satisfy I0 */ ]
+
+type I01 interface {
+       E0
+       E1
+}
+
+func f01[T I01]()
+var _ = f01[int]
+var _ = f01[bool /* ERROR does not satisfy I0 */ ]
+var _ = f01[string]
+var _ = f01[float64 /* ERROR does not satisfy I0 */ ]
+
+type I012 interface {
+       E0
+       E1
+       E2
+}
+
+func f012[T I012]()
+var _ = f012[int /* ERROR does not satisfy I012 */ ]
+var _ = f012[bool /* ERROR does not satisfy I012 */ ]
+var _ = f012[string /* ERROR does not satisfy I012 */ ]
+var _ = f012[float64 /* ERROR does not satisfy I012 */ ]
+
+type I12 interface {
+       E1
+       E2
+}
+
+func f12[T I12]()
+var _ = f12[int /* ERROR does not satisfy I12 */ ]
+var _ = f12[bool /* ERROR does not satisfy I12 */ ]
+var _ = f12[string /* ERROR does not satisfy I12 */ ]
+var _ = f12[float64]
+
+type I0_ interface {
+       E0
+       type int
+}
+
+func f0_[T I0_]()
+var _ = f0_[int]
+var _ = f0_[bool /* ERROR does not satisfy I0_ */ ]
+var _ = f0_[string /* ERROR does not satisfy I0_ */ ]
+var _ = f0_[float64 /* ERROR does not satisfy I0_ */ ]
diff --git a/src/cmd/compile/internal/syntax/testdata/go2/typeparams.go2 b/src/cmd/compile/internal/syntax/testdata/go2/typeparams.go2
new file mode 100644 (file)
index 0000000..f78037f
--- /dev/null
@@ -0,0 +1,451 @@
+// Copyright 2018 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
+
+// import "io" // for type assertion tests
+
+// The predeclared identifier "any" is only visible as a constraint
+// in a type parameter list.
+var _ any // ERROR undeclared
+func _[_ any /* ok here */ , _ interface{any /* ERROR undeclared */ }](any /* ERROR undeclared */ ) {
+        var _ any /* ERROR undeclared */
+}
+
+func identity[T any](x T) T { return x }
+
+func _[_ any](x int) int
+func _[T any](T /* ERROR redeclared */ T)()
+func _[T, T /* ERROR redeclared */ any]()
+
+func reverse[T any](list []T) []T {
+        rlist := make([]T, len(list))
+        i := len(list)
+        for _, x := range list {
+                i--
+                rlist[i] = x
+        }
+        return rlist
+}
+
+var _ = reverse /* ERROR cannot use generic function reverse */
+var _ = reverse[int, float32 /* ERROR got 2 type arguments */ ] ([]int{1, 2, 3})
+var _ = reverse[int]([ /* ERROR cannot use */ ]float32{1, 2, 3})
+var f = reverse[chan int]
+var _ = f(0 /* ERROR cannot convert 0 .* to \[\]chan int */ )
+
+func swap[A, B any](a A, b B) (B, A) { return b, a }
+
+var _ = swap /* ERROR single value is expected */ [int, float32](1, 2)
+var f32, i = swap[int, float32](swap(float32, int)(1, 2))
+var _ float32 = f32
+var _ int = i
+
+func swapswap[A, B any](a A, b B) (A, B) {
+        return swap[B, A](b, a)
+}
+
+type F[A, B any] func(A, B) (B, A)
+
+func min[T interface{ type int }](x, y T) T {
+        if x < y {
+                return x
+        }
+        return y
+}
+
+func _[T interface{type int, float32}](x, y T) bool { return x < y }
+func _[T any](x, y T) bool { return x /* ERROR cannot compare */ < y }
+func _[T interface{type int, float32, bool}](x, y T) bool { return x /* ERROR cannot compare */ < y }
+
+func _[T C1[T]](x, y T) bool { return x /* ERROR cannot compare */ < y }
+func _[T C2[T]](x, y T) bool { return x < y }
+
+type C1[T any] interface{}
+type C2[T any] interface{ type int, float32 }
+
+func new[T any]() *T {
+        var x T
+        return &x
+}
+
+var _ = new /* ERROR cannot use generic function new */
+var _ *int = new[int]()
+
+func _[T any](map[T /* ERROR invalid map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable
+
+func f1[T1 any](struct{T1}) int
+var _ = f1(int)(struct{T1}{})
+type T1 = int
+
+func f2[t1 any](struct{t1; x float32}) int
+var _ = f2(t1)(struct{t1; x float32}{})
+type t1 = int
+
+
+func f3[A, B, C any](A, struct{x B}, func(A, struct{x B}, *C)) int
+
+var _ = f3[int, rune, bool](1, struct{x rune}{}, nil)
+
+// indexing
+
+func _[T any] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
+func _[T interface{ type int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
+func _[T interface{ type string }] (x T, i int) { _ = x[i] }
+func _[T interface{ type []int }] (x T, i int) { _ = x[i] }
+func _[T interface{ type [10]int, *[20]int, map[string]int }] (x T, i int) { _ = x[i] }
+func _[T interface{ type string, []byte }] (x T, i int) { _ = x[i] }
+func _[T interface{ type []int, [1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
+func _[T interface{ type string, []rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
+
+// slicing
+// TODO(gri) implement this
+
+func _[T interface{ type string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] }
+
+// len/cap built-ins
+
+func _[T any](x T) { _ = len(x /* ERROR invalid argument */ ) }
+func _[T interface{ type int }](x T) { _ = len(x /* ERROR invalid argument */ ) }
+func _[T interface{ type string, []byte, int }](x T) { _ = len(x /* ERROR invalid argument */ ) }
+func _[T interface{ type string }](x T) { _ = len(x) }
+func _[T interface{ type [10]int }](x T) { _ = len(x) }
+func _[T interface{ type []byte }](x T) { _ = len(x) }
+func _[T interface{ type map[int]int }](x T) { _ = len(x) }
+func _[T interface{ type chan int }](x T) { _ = len(x) }
+func _[T interface{ type string, []byte, chan int }](x T) { _ = len(x) }
+
+func _[T any](x T) { _ = cap(x /* ERROR invalid argument */ ) }
+func _[T interface{ type int }](x T) { _ = cap(x /* ERROR invalid argument */ ) }
+func _[T interface{ type string, []byte, int }](x T) { _ = cap(x /* ERROR invalid argument */ ) }
+func _[T interface{ type string }](x T) { _ = cap(x /* ERROR invalid argument */ ) }
+func _[T interface{ type [10]int }](x T) { _ = cap(x) }
+func _[T interface{ type []byte }](x T) { _ = cap(x) }
+func _[T interface{ type map[int]int }](x T) { _ = cap(x /* ERROR invalid argument */ ) }
+func _[T interface{ type chan int }](x T) { _ = cap(x) }
+func _[T interface{ type []byte, chan int }](x T) { _ = cap(x) }
+
+// range iteration
+
+func _[T interface{}](x T) {
+        for range x /* ERROR cannot range */ {}
+}
+
+func _[T interface{ type string, []string }](x T) {
+        for range x {}
+        for i := range x { _ = i }
+        for i, _ := range x { _ = i }
+        for i, e := range x /* ERROR must have the same element type */ { _ = i }
+        for _, e := range x /* ERROR must have the same element type */ {}
+        var e rune
+        _ = e
+        for _, (e) = range x /* ERROR must have the same element type */ {}
+}
+
+
+func _[T interface{ type string, []rune, map[int]rune }](x T) {
+        for _, e := range x { _ = e }
+        for i, e := range x { _ = i; _ = e }
+}
+
+func _[T interface{ type string, []rune, map[string]rune }](x T) {
+        for _, e := range x { _ = e }
+        for i, e := range x /* ERROR must have the same key type */ { _ = e }
+}
+
+func _[T interface{ type string, chan int }](x T) {
+        for range x {}
+        for i := range x { _ = i }
+        for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value
+}
+
+func _[T interface{ type string, chan<-int }](x T) {
+        for i := range x /* ERROR send-only channel */ { _ = i }
+}
+
+// type inference checks
+
+var _ = new() /* ERROR cannot infer T */
+
+func f4[A, B, C any](A, B) C
+
+var _ = f4(1, 2) /* ERROR cannot infer C */
+var _ = f4[int, float32, complex128](1, 2)
+
+func f5[A, B, C any](A, []*B, struct{f []C}) int
+
+var _ = f5[int, float32, complex128](0, nil, struct{f []complex128}{})
+var _ = f5(0, nil, struct{f []complex128}{}) // ERROR cannot infer
+var _ = f5(0, []*float32{new[float32]()}, struct{f []complex128}{})
+
+func f6[A any](A, []A) int
+
+var _ = f6(0, nil)
+
+func f6nil[A any](A) int
+
+var _ = f6nil(nil) // ERROR cannot infer
+
+// type inference with variadic functions
+
+func f7[T any](...T) T
+
+var _ int = f7() /* ERROR cannot infer T */
+var _ int = f7(1)
+var _ int = f7(1, 2)
+var _ int = f7([]int{}...)
+var _ int = f7 /* ERROR cannot use */ ([]float64{}...)
+var _ float64 = f7([]float64{}...)
+var _ = f7[float64](1, 2.3)
+var _ = f7(float64(1), 2.3)
+var _ = f7(1, 2.3 /* ERROR does not match */ )
+var _ = f7(1.2, 3 /* ERROR does not match */ )
+
+func f8[A, B any](A, B, ...B) int
+
+var _ = f8(1) /* ERROR not enough arguments */
+var _ = f8(1, 2.3)
+var _ = f8(1, 2.3, 3.4, 4.5)
+var _ = f8(1, 2.3, 3.4, 4 /* ERROR does not match */ )
+var _ = f8(int, float64)(1, 2.3, 3.4, 4)
+
+var _ = f8(int, float64)(0, 0, nil...) // test case for #18268
+
+// init functions cannot have type parameters
+
+func init() {}
+func init[/* ERROR func init must have no type parameters */ _ any]() {}
+func init[/* ERROR func init must have no type parameters */ P any]() {}
+
+type T struct {}
+
+func (T) m1() {}
+// The type checker accepts method type parameters if configured accordingly.
+func (T) m2[_ any]() {}
+func (T) m3[P any]() {}
+
+// type inference across parameterized types
+
+type S1[P any] struct { f P }
+
+func f9[P any](x S1[P])
+
+func _() {
+        f9[int](S1[int]{42})
+       f9(S1[int]{42})
+}
+
+type S2[A, B, C any] struct{}
+
+func f10[X, Y, Z any](a S2[X, int, Z], b S2[X, Y, bool])
+
+func _[P any]() {
+        f10[int, float32, string](S2[int, int, string]{}, S2[int, float32, bool]{})
+        f10(S2[int, int, string]{}, S2[int, float32, bool]{})
+        f10(S2[P, int, P]{}, S2[P, float32, bool]{})
+}
+
+// corner case for type inference
+// (was bug: after instanting f11, the type-checker didn't mark f11 as non-generic)
+
+func f11[T any]()
+
+func _() {
+       f11[int]()
+}
+
+// the previous example was extracted from
+
+func f12[T interface{m() T}]()
+
+type A[T any] T
+
+func (a A[T]) m() A[T]
+
+func _[T any]() {
+       f12(A[T])()
+}
+
+// method expressions
+
+func (_ S1[P]) m()
+
+func _() {
+       m := S1[int].m
+       m(struct { f int }{42})
+}
+
+func _[T any] (x T) {
+        m := S1[T].m
+        m(S1[T]{x})
+}
+
+// type parameters in methods (generalization)
+
+type R0 struct{}
+
+func (R0) _[T any](x T)
+func (R0 /* ERROR invalid receiver */ ) _[R0 any]() // scope of type parameters starts at "func"
+
+type R1[A, B any] struct{}
+
+func (_ R1[A, B]) m0(A, B)
+func (_ R1[A, B]) m1[T any](A, B, T) T
+func (_ R1 /* ERROR not a generic type */ [R1, _]) _()
+func (_ R1[A, B]) _[A /* ERROR redeclared */ any](B)
+
+func _() {
+        var r R1[int, string]
+        r.m1[rune](42, "foo", 'a')
+        r.m1[rune](42, "foo", 1.2 /* ERROR truncated to rune */)
+        r.m1(42, "foo", 1.2) // using type inference
+        var _ float64 = r.m1(42, "foo", 1.2)
+}
+
+type I1[A any] interface {
+        m1(A)
+}
+
+var _ I1[int] = r1[int]{}
+
+type r1[T any] struct{}
+
+func (_ r1[T]) m1(T)
+
+type I2[A, B any] interface {
+        m1(A)
+        m2(A) B
+}
+
+var _ I2[int, float32] = R2[int, float32]{}
+
+type R2[P, Q any] struct{}
+
+func (_ R2[X, Y]) m1(X)
+func (_ R2[X, Y]) m2(X) Y
+
+// type assertions and type switches over generic types
+// NOTE: These are currently disabled because it's unclear what the correct
+// approach is, and one can always work around by assigning the variable to
+// an interface first.
+
+// // ReadByte1 corresponds to the ReadByte example in the draft design.
+// func ReadByte1[T io.Reader](r T) (byte, error) {
+//     if br, ok := r.(io.ByteReader); ok {
+//             return br.ReadByte()
+//     }
+//     var b [1]byte
+//     _, err := r.Read(b[:])
+//     return b[0], err
+// }
+//
+// // ReadBytes2 is like ReadByte1 but uses a type switch instead.
+// func ReadByte2[T io.Reader](r T) (byte, error) {
+//         switch br := r.(type) {
+//         case io.ByteReader:
+//                 return br.ReadByte()
+//         }
+//     var b [1]byte
+//     _, err := r.Read(b[:])
+//     return b[0], err
+// }
+//
+// // type assertions and type switches over generic types are strict
+// type I3 interface {
+//         m(int)
+// }
+//
+// type I4 interface {
+//         m() int // different signature from I3.m
+// }
+//
+// func _[T I3](x I3, p T) {
+//         // type assertions and type switches over interfaces are not strict
+//         _ = x.(I4)
+//         switch x.(type) {
+//         case I4:
+//         }
+// 
+//         // type assertions and type switches over generic types are strict
+//         _ = p /* ERROR cannot have dynamic type I4 */.(I4)
+//         switch p.(type) {
+//         case I4 /* ERROR cannot have dynamic type I4 */ :
+//         }
+// }
+
+// type assertions and type switches over generic types lead to errors for now
+
+func _[T any](x T) {
+       _ = x /* ERROR not an interface */ .(int)
+       switch x /* ERROR not an interface */ .(type) {
+       }
+
+       // work-around
+       var t interface{} = x
+       _ = t.(int)
+       switch t.(type) {
+       }
+}
+
+func _[T interface{type int}](x T) {
+       _ = x /* ERROR not an interface */ .(int)
+       switch x /* ERROR not an interface */ .(type) {
+       }
+
+       // work-around
+       var t interface{} = x
+       _ = t.(int)
+       switch t.(type) {
+       }
+}
+
+// error messages related to type bounds mention those bounds
+type C[P any] interface{}
+
+func _[P C[P]] (x P) {
+       x.m /* ERROR x.m undefined */ ()
+}
+
+type I interface {}
+
+func _[P I] (x P) {
+       x.m /* ERROR interface I has no method m */ ()
+}
+
+func _[P interface{}] (x P) {
+       x.m /* ERROR type bound for P has no method m */ ()
+}
+
+func _[P any] (x P) {
+       x.m /* ERROR type bound for P has no method m */ ()
+}
+
+// automatic distinguishing between array and generic types
+// NOTE: Disabled when using unified parameter list syntax.
+/*
+const P = 10
+type A1 [P]byte
+func _(a A1) {
+        assert(len(a) == 10)
+}
+
+type A2 [P]struct{
+        f [P]byte
+}
+func _(a A2) {
+        assert(len(a) == 10)
+        assert(len(a[0].f) == 10)
+}
+
+type A3 [P]func(x [P]A3)
+func _(a A3) {
+        assert(len(a) == 10)
+}
+
+type T2[P] struct{ P }
+var _ T2[int]
+
+type T3[P] func(P)
+var _ T3[int]
+*/
\ No newline at end of file
diff --git a/src/cmd/compile/internal/syntax/testdata/tparams.go2 b/src/cmd/compile/internal/syntax/testdata/tparams.go2
new file mode 100644 (file)
index 0000000..42031c3
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2020 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 t[ /* ERROR type parameters must be named */ a, b] struct{}
+type t[a t, b t, /* ERROR type parameters must be named */ c] struct{}
+type t struct {
+       t [n]byte
+       t[a]
+       t[a, b]
+}
+type t interface {
+       t[a]
+       m /* ERROR method cannot have type parameters */ [_ _, /* ERROR mixed */ _]()
+       t[a, b]
+}
+
+func f[ /* ERROR empty type parameter list */ ]()
+func f[ /* ERROR type parameters must be named */ a, b]()
+func f[a t, b t, /* ERROR type parameters must be named */ c]()
diff --git a/src/cmd/compile/internal/syntax/testing.go b/src/cmd/compile/internal/syntax/testing.go
new file mode 100644 (file)
index 0000000..3e02dc1
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright 2020 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.
+
+// This file implements testing support.
+
+package syntax
+
+import (
+       "io"
+       "regexp"
+       "strings"
+)
+
+// CommentsDo parses the given source and calls the provided handler for each
+// comment or error. If the text provided to handler starts with a '/' it is
+// the comment text; otherwise it is the error message.
+func CommentsDo(src io.Reader, handler func(line, col uint, text string)) {
+       var s scanner
+       s.init(src, handler, comments)
+       for s.tok != _EOF {
+               s.next()
+       }
+}
+
+// ERROR comments must start with text `ERROR "msg"` or `ERROR msg`.
+// Space around "msg" or msg is ignored.
+var errRx = regexp.MustCompile(`^ *ERROR *"?([^"]*)"?`)
+
+// ErrorMap collects all comments with comment text of the form
+// `ERROR "msg"` or `ERROR msg` from the given src and returns them
+// as []Error lists in a map indexed by line number. The position
+// for each Error is the position of the token immediately preceding
+// the comment, the Error message is the message msg extracted from
+// the comment, with all errors that are on the same line collected
+// in a slice. If there is no preceding token (the `ERROR` comment
+// appears in the beginning of the file), then the recorded position
+// is unknown (line, col = 0, 0). If there are no ERROR comments, the
+// result is nil.
+func ErrorMap(src io.Reader) (errmap map[uint][]Error) {
+       // position of previous token
+       var base *PosBase
+       var prev struct{ line, col uint }
+
+       var s scanner
+       s.init(src, func(_, _ uint, text string) {
+               if text[0] != '/' {
+                       return // error, ignore
+               }
+               if text[1] == '*' {
+                       text = text[:len(text)-2] // strip trailing */
+               }
+               if s := errRx.FindStringSubmatch(text[2:]); len(s) == 2 {
+                       pos := MakePos(base, prev.line, prev.col)
+                       err := Error{pos, strings.TrimSpace(s[1])}
+                       if errmap == nil {
+                               errmap = make(map[uint][]Error)
+                       }
+                       errmap[prev.line] = append(errmap[prev.line], err)
+               }
+       }, comments)
+
+       for s.tok != _EOF {
+               s.next()
+               if s.tok == _Semi && s.lit != "semicolon" {
+                       continue // ignore automatically inserted semicolons
+               }
+               prev.line, prev.col = s.line, s.col
+       }
+
+       return
+}
diff --git a/src/cmd/compile/internal/syntax/testing_test.go b/src/cmd/compile/internal/syntax/testing_test.go
new file mode 100644 (file)
index 0000000..d34e5ea
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2020 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 syntax
+
+import (
+       "fmt"
+       "strings"
+       "testing"
+)
+
+func TestErrorMap(t *testing.T) {
+       const src = `/* ERROR 0:0 */ /* ERROR "0:0" */ // ERROR 0:0
+// ERROR "0:0"
+x /* ERROR 3:1 */                // ignore automatically inserted semicolon here
+/* ERROR 3:1 */                  // position of x on previous line
+   x /* ERROR 5:4 */ ;           // do not ignore this semicolon
+/* ERROR 5:22 */                 // position of ; on previous line
+       package /* ERROR 7:2 */  // indented with tab
+        import  /* ERROR 8:9 */  // indented with blanks
+`
+       m := ErrorMap(strings.NewReader(src))
+       got := 0 // number of errors found
+       for line, errlist := range m {
+               for _, err := range errlist {
+                       if err.Pos.Line() != line {
+                               t.Errorf("%v: got map line %d; want %d", err, err.Pos.Line(), line)
+                               continue
+                       }
+                       // err.Pos.Line() == line
+                       msg := fmt.Sprintf("%d:%d", line, err.Pos.Col())
+                       if err.Msg != msg {
+                               t.Errorf("%v: got msg %q; want %q", err, err.Msg, msg)
+                               continue
+                       }
+               }
+               got += len(errlist)
+       }
+
+       want := strings.Count(src, "ERROR")
+       if got != want {
+               t.Errorf("ErrorMap got %d errors; want %d", got, want)
+       }
+}
diff --git a/src/cmd/compile/internal/types2/api.go b/src/cmd/compile/internal/types2/api.go
new file mode 100644 (file)
index 0000000..c5c30ba
--- /dev/null
@@ -0,0 +1,436 @@
+// UNREVIEWED
+// Copyright 2012 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 types declares the data types and implements
+// the algorithms for type-checking of Go packages. Use
+// Config.Check to invoke the type checker for a package.
+// Alternatively, create a new type checker with NewChecker
+// and invoke it incrementally by calling Checker.Files.
+//
+// Type-checking consists of several interdependent phases:
+//
+// Name resolution maps each identifier (syntax.Name) in the program to the
+// language object (Object) it denotes.
+// Use Info.{Defs,Uses,Implicits} for the results of name resolution.
+//
+// Constant folding computes the exact constant value (constant.Value)
+// for every expression (syntax.Expr) that is a compile-time constant.
+// Use Info.Types[expr].Value for the results of constant folding.
+//
+// Type inference computes the type (Type) of every expression (syntax.Expr)
+// and checks for compliance with the language specification.
+// Use Info.Types[expr].Type for the results of type inference.
+//
+// For a tutorial, see https://golang.org/s/types-tutorial.
+//
+package types2
+
+import (
+       "bytes"
+       "cmd/compile/internal/syntax"
+       "fmt"
+       "go/constant"
+)
+
+// An Error describes a type-checking error; it implements the error interface.
+// A "soft" error is an error that still permits a valid interpretation of a
+// package (such as "unused variable"); "hard" errors may lead to unpredictable
+// behavior if ignored.
+type Error struct {
+       Pos  syntax.Pos // error position
+       Msg  string     // default error message, user-friendly
+       Full string     // full error message, for debugging (may contain internal details)
+       Soft bool       // if set, error is "soft"
+}
+
+// Error returns an error string formatted as follows:
+// filename:line:column: message
+func (err Error) Error() string {
+       return fmt.Sprintf("%s: %s", err.Pos, err.Msg)
+}
+
+// FullError returns an error string like Error, buy it may contain
+// type-checker internal details such as subscript indices for type
+// parameters and more. Useful for debugging.
+func (err Error) FullError() string {
+       return fmt.Sprintf("%s: %s", err.Pos, err.Full)
+}
+
+// An Importer resolves import paths to Packages.
+//
+// CAUTION: This interface does not support the import of locally
+// vendored packages. See https://golang.org/s/go15vendor.
+// If possible, external implementations should implement ImporterFrom.
+type Importer interface {
+       // Import returns the imported package for the given import path.
+       // The semantics is like for ImporterFrom.ImportFrom except that
+       // dir and mode are ignored (since they are not present).
+       Import(path string) (*Package, error)
+}
+
+// ImportMode is reserved for future use.
+type ImportMode int
+
+// An ImporterFrom resolves import paths to packages; it
+// supports vendoring per https://golang.org/s/go15vendor.
+// Use go/importer to obtain an ImporterFrom implementation.
+type ImporterFrom interface {
+       // Importer is present for backward-compatibility. Calling
+       // Import(path) is the same as calling ImportFrom(path, "", 0);
+       // i.e., locally vendored packages may not be found.
+       // The types package does not call Import if an ImporterFrom
+       // is present.
+       Importer
+
+       // ImportFrom returns the imported package for the given import
+       // path when imported by a package file located in dir.
+       // If the import failed, besides returning an error, ImportFrom
+       // is encouraged to cache and return a package anyway, if one
+       // was created. This will reduce package inconsistencies and
+       // follow-on type checker errors due to the missing package.
+       // The mode value must be 0; it is reserved for future use.
+       // Two calls to ImportFrom with the same path and dir must
+       // return the same package.
+       ImportFrom(path, dir string, mode ImportMode) (*Package, error)
+}
+
+// A Config specifies the configuration for type checking.
+// The zero value for Config is a ready-to-use default configuration.
+type Config struct {
+       // If IgnoreFuncBodies is set, function bodies are not
+       // type-checked.
+       IgnoreFuncBodies bool
+
+       // If AcceptMethodTypeParams is set, methods may have type parameters.
+       AcceptMethodTypeParams bool
+
+       // If InferFromConstraints is set, constraint type inference is used
+       // if some function type arguments are missing.
+       InferFromConstraints bool
+
+       // If FakeImportC is set, `import "C"` (for packages requiring Cgo)
+       // declares an empty "C" package and errors are omitted for qualified
+       // identifiers referring to package C (which won't find an object).
+       // This feature is intended for the standard library cmd/api tool.
+       //
+       // Caution: Effects may be unpredictable due to follow-on errors.
+       //          Do not use casually!
+       FakeImportC bool
+
+       // If IgnoreBranches is set, errors related to incorrectly placed
+       // labels, gotos, break, continue, and fallthrough statements are
+       // ignored.
+       IgnoreBranches bool
+
+       // If CompilerErrorMessages is set, errors are reported using
+       // cmd/compile error strings to match $GOROOT/test errors.
+       // TODO(gri) Consolidate error messages and remove this flag.
+       CompilerErrorMessages bool
+
+       // If go115UsesCgo is set, the type checker expects the
+       // _cgo_gotypes.go file generated by running cmd/cgo to be
+       // provided as a package source file. Qualified identifiers
+       // referring to package C will be resolved to cgo-provided
+       // declarations within _cgo_gotypes.go.
+       //
+       // It is an error to set both FakeImportC and go115UsesCgo.
+       go115UsesCgo bool
+
+       // If Trace is set, a debug trace is printed to stdout.
+       Trace bool
+
+       // If Error != nil, it is called with each error found
+       // during type checking; err has dynamic type Error.
+       // Secondary errors (for instance, to enumerate all types
+       // involved in an invalid recursive type declaration) have
+       // error strings that start with a '\t' character.
+       // If Error == nil, type-checking stops with the first
+       // error found.
+       Error func(err error)
+
+       // An importer is used to import packages referred to from
+       // import declarations.
+       // If the installed importer implements ImporterFrom, the type
+       // checker calls ImportFrom instead of Import.
+       // The type checker reports an error if an importer is needed
+       // but none was installed.
+       Importer Importer
+
+       // If Sizes != nil, it provides the sizing functions for package unsafe.
+       // Otherwise SizesFor("gc", "amd64") is used instead.
+       Sizes Sizes
+
+       // If DisableUnusedImportCheck is set, packages are not checked
+       // for unused imports.
+       DisableUnusedImportCheck bool
+}
+
+func srcimporter_setUsesCgo(conf *Config) {
+       conf.go115UsesCgo = true
+}
+
+// Info holds result type information for a type-checked package.
+// Only the information for which a map is provided is collected.
+// If the package has type errors, the collected information may
+// be incomplete.
+type Info struct {
+       // Types maps expressions to their types, and for constant
+       // expressions, also their values. Invalid expressions are
+       // omitted.
+       //
+       // For (possibly parenthesized) identifiers denoting built-in
+       // functions, the recorded signatures are call-site specific:
+       // if the call result is not a constant, the recorded type is
+       // an argument-specific signature. Otherwise, the recorded type
+       // is invalid.
+       //
+       // The Types map does not record the type of every identifier,
+       // only those that appear where an arbitrary expression is
+       // permitted. For instance, the identifier f in a selector
+       // expression x.f is found only in the Selections map, the
+       // identifier z in a variable declaration 'var z int' is found
+       // only in the Defs map, and identifiers denoting packages in
+       // qualified identifiers are collected in the Uses map.
+       Types map[syntax.Expr]TypeAndValue
+
+       // Inferred maps calls of parameterized functions that use
+       // type inference to the inferred type arguments and signature
+       // of the function called. The recorded "call" expression may be
+       // an *ast.CallExpr (as in f(x)), or an *ast.IndexExpr (s in f[T]).
+       Inferred map[syntax.Expr]Inferred
+
+       // Defs maps identifiers to the objects they define (including
+       // package names, dots "." of dot-imports, and blank "_" identifiers).
+       // For identifiers that do not denote objects (e.g., the package name
+       // in package clauses, or symbolic variables t in t := x.(type) of
+       // type switch headers), the corresponding objects are nil.
+       //
+       // For an embedded field, Defs returns the field *Var it defines.
+       //
+       // Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
+       Defs map[*syntax.Name]Object
+
+       // Uses maps identifiers to the objects they denote.
+       //
+       // For an embedded field, Uses returns the *TypeName it denotes.
+       //
+       // Invariant: Uses[id].Pos() != id.Pos()
+       Uses map[*syntax.Name]Object
+
+       // Implicits maps nodes to their implicitly declared objects, if any.
+       // The following node and object types may appear:
+       //
+       //     node               declared object
+       //
+       //     *syntax.ImportDecl    *PkgName for imports without renames
+       //     *syntax.CaseClause    type-specific *Var for each type switch case clause (incl. default)
+       //     *syntax.Field         anonymous parameter *Var (incl. unnamed results)
+       //
+       Implicits map[syntax.Node]Object
+
+       // Selections maps selector expressions (excluding qualified identifiers)
+       // to their corresponding selections.
+       Selections map[*syntax.SelectorExpr]*Selection
+
+       // Scopes maps syntax.Nodes to the scopes they define. Package scopes are not
+       // associated with a specific node but with all files belonging to a package.
+       // Thus, the package scope can be found in the type-checked Package object.
+       // Scopes nest, with the Universe scope being the outermost scope, enclosing
+       // the package scope, which contains (one or more) files scopes, which enclose
+       // function scopes which in turn enclose statement and function literal scopes.
+       // Note that even though package-level functions are declared in the package
+       // scope, the function scopes are embedded in the file scope of the file
+       // containing the function declaration.
+       //
+       // The following node types may appear in Scopes:
+       //
+       //     *syntax.File
+       //     *syntax.FuncType
+       //     *syntax.BlockStmt
+       //     *syntax.IfStmt
+       //     *syntax.SwitchStmt
+       //     *syntax.CaseClause
+       //     *syntax.CommClause
+       //     *syntax.ForStmt
+       //
+       Scopes map[syntax.Node]*Scope
+
+       // InitOrder is the list of package-level initializers in the order in which
+       // they must be executed. Initializers referring to variables related by an
+       // initialization dependency appear in topological order, the others appear
+       // in source order. Variables without an initialization expression do not
+       // appear in this list.
+       InitOrder []*Initializer
+}
+
+// TypeOf returns the type of expression e, or nil if not found.
+// Precondition: the Types, Uses and Defs maps are populated.
+//
+func (info *Info) TypeOf(e syntax.Expr) Type {
+       if t, ok := info.Types[e]; ok {
+               return t.Type
+       }
+       if id, _ := e.(*syntax.Name); id != nil {
+               if obj := info.ObjectOf(id); obj != nil {
+                       return obj.Type()
+               }
+       }
+       return nil
+}
+
+// ObjectOf returns the object denoted by the specified id,
+// or nil if not found.
+//
+// If id is an embedded struct field, ObjectOf returns the field (*Var)
+// it defines, not the type (*TypeName) it uses.
+//
+// Precondition: the Uses and Defs maps are populated.
+//
+func (info *Info) ObjectOf(id *syntax.Name) Object {
+       if obj := info.Defs[id]; obj != nil {
+               return obj
+       }
+       return info.Uses[id]
+}
+
+// TypeAndValue reports the type and value (for constants)
+// of the corresponding expression.
+type TypeAndValue struct {
+       mode  operandMode
+       Type  Type
+       Value constant.Value
+}
+
+// IsVoid reports whether the corresponding expression
+// is a function call without results.
+func (tv TypeAndValue) IsVoid() bool {
+       return tv.mode == novalue
+}
+
+// IsType reports whether the corresponding expression specifies a type.
+func (tv TypeAndValue) IsType() bool {
+       return tv.mode == typexpr
+}
+
+// IsBuiltin reports whether the corresponding expression denotes
+// a (possibly parenthesized) built-in function.
+func (tv TypeAndValue) IsBuiltin() bool {
+       return tv.mode == builtin
+}
+
+// IsValue reports whether the corresponding expression is a value.
+// Builtins are not considered values. Constant values have a non-
+// nil Value.
+func (tv TypeAndValue) IsValue() bool {
+       switch tv.mode {
+       case constant_, variable, mapindex, value, commaok, commaerr:
+               return true
+       }
+       return false
+}
+
+// IsNil reports whether the corresponding expression denotes the
+// predeclared value nil.
+func (tv TypeAndValue) IsNil() bool {
+       return tv.mode == value && tv.Type == Typ[UntypedNil]
+}
+
+// Addressable reports whether the corresponding expression
+// is addressable (https://golang.org/ref/spec#Address_operators).
+func (tv TypeAndValue) Addressable() bool {
+       return tv.mode == variable
+}
+
+// Assignable reports whether the corresponding expression
+// is assignable to (provided a value of the right type).
+func (tv TypeAndValue) Assignable() bool {
+       return tv.mode == variable || tv.mode == mapindex
+}
+
+// HasOk reports whether the corresponding expression may be
+// used on the rhs of a comma-ok assignment.
+func (tv TypeAndValue) HasOk() bool {
+       return tv.mode == commaok || tv.mode == mapindex
+}
+
+// Inferred reports the inferred type arguments and signature
+// for a parameterized function call that uses type inference.
+type Inferred struct {
+       Targs []Type
+       Sig   *Signature
+}
+
+// An Initializer describes a package-level variable, or a list of variables in case
+// of a multi-valued initialization expression, and the corresponding initialization
+// expression.
+type Initializer struct {
+       Lhs []*Var // var Lhs = Rhs
+       Rhs syntax.Expr
+}
+
+func (init *Initializer) String() string {
+       var buf bytes.Buffer
+       for i, lhs := range init.Lhs {
+               if i > 0 {
+                       buf.WriteString(", ")
+               }
+               buf.WriteString(lhs.Name())
+       }
+       buf.WriteString(" = ")
+       WriteExpr(&buf, init.Rhs)
+       return buf.String()
+}
+
+// Check type-checks a package and returns the resulting package object and
+// the first error if any. Additionally, if info != nil, Check populates each
+// of the non-nil maps in the Info struct.
+//
+// The package is marked as complete if no errors occurred, otherwise it is
+// incomplete. See Config.Error for controlling behavior in the presence of
+// errors.
+//
+// The package is specified by a list of *syntax.Files and corresponding
+// file set, and the package path the package is identified with.
+// The clean path must not be empty or dot (".").
+func (conf *Config) Check(path string, files []*syntax.File, info *Info) (*Package, error) {
+       pkg := NewPackage(path, "")
+       return pkg, NewChecker(conf, pkg, info).Files(files)
+}
+
+// AssertableTo reports whether a value of type V can be asserted to have type T.
+func AssertableTo(V *Interface, T Type) bool {
+       m, _ := (*Checker)(nil).assertableTo(V, T, false)
+       return m == nil
+}
+
+// AssignableTo reports whether a value of type V is assignable to a variable of type T.
+func AssignableTo(V, T Type) bool {
+       x := operand{mode: value, typ: V}
+       return x.assignableTo(nil, T, nil) // check not needed for non-constant x
+}
+
+// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
+func ConvertibleTo(V, T Type) bool {
+       x := operand{mode: value, typ: V}
+       return x.convertibleTo(nil, T) // check not needed for non-constant x
+}
+
+// Implements reports whether type V implements interface T.
+func Implements(V Type, T *Interface) bool {
+       f, _ := MissingMethod(V, T, true)
+       return f == nil
+}
+
+// Identical reports whether x and y are identical types.
+// Receivers of Signature types are ignored.
+func Identical(x, y Type) bool {
+       return (*Checker)(nil).identical(x, y)
+}
+
+// IdenticalIgnoreTags reports whether x and y are identical types if tags are ignored.
+// Receivers of Signature types are ignored.
+func IdenticalIgnoreTags(x, y Type) bool {
+       return (*Checker)(nil).identicalIgnoreTags(x, y)
+}
diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go
new file mode 100644 (file)
index 0000000..58d7df2
--- /dev/null
@@ -0,0 +1,1741 @@
+// UNREVIEWED
+// Copyright 2013 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 (
+       "bytes"
+       "cmd/compile/internal/syntax"
+       "fmt"
+       "internal/testenv"
+       "reflect"
+       "regexp"
+       "strings"
+       "testing"
+
+       . "cmd/compile/internal/types2"
+)
+
+func unimplemented() {
+       panic("unimplemented")
+}
+
+func parseSrc(path, src string) (*syntax.File, error) {
+       errh := func(error) {} // dummy error handler so that parsing continues in presence of errors
+       return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, syntax.AllowGenerics)
+}
+
+func pkgFor(path, source string, info *Info) (*Package, error) {
+       f, err := parseSrc(path, source)
+       if err != nil {
+               return nil, err
+       }
+       conf := Config{Importer: defaultImporter()}
+       return conf.Check(f.PkgName.Value, []*syntax.File{f}, info)
+}
+
+func mustTypecheck(t *testing.T, path, source string, info *Info) string {
+       pkg, err := pkgFor(path, source, info)
+       if err != nil {
+               name := path
+               if pkg != nil {
+                       name = "package " + pkg.Name()
+               }
+               t.Fatalf("%s: didn't type-check (%s)", name, err)
+       }
+       return pkg.Name()
+}
+
+func mayTypecheck(t *testing.T, path, source string, info *Info) (string, error) {
+       f, err := parseSrc(path, source)
+       if f == nil { // ignore errors unless f is nil
+               t.Fatalf("%s: unable to parse: %s", path, err)
+       }
+       conf := Config{
+               AcceptMethodTypeParams: true,
+               InferFromConstraints:   true,
+               Error:                  func(err error) {},
+               Importer:               defaultImporter(),
+       }
+       pkg, err := conf.Check(f.PkgName.Value, []*syntax.File{f}, info)
+       return pkg.Name(), err
+}
+
+func TestValuesInfo(t *testing.T) {
+       var tests = []struct {
+               src  string
+               expr string // constant expression
+               typ  string // constant type
+               val  string // constant value
+       }{
+               {`package a0; const _ = false`, `false`, `untyped bool`, `false`},
+               {`package a1; const _ = 0`, `0`, `untyped int`, `0`},
+               {`package a2; const _ = 'A'`, `'A'`, `untyped rune`, `65`},
+               {`package a3; const _ = 0.`, `0.`, `untyped float`, `0`},
+               {`package a4; const _ = 0i`, `0i`, `untyped complex`, `(0 + 0i)`},
+               {`package a5; const _ = "foo"`, `"foo"`, `untyped string`, `"foo"`},
+
+               {`package b0; var _ = false`, `false`, `bool`, `false`},
+               {`package b1; var _ = 0`, `0`, `int`, `0`},
+               {`package b2; var _ = 'A'`, `'A'`, `rune`, `65`},
+               {`package b3; var _ = 0.`, `0.`, `float64`, `0`},
+               {`package b4; var _ = 0i`, `0i`, `complex128`, `(0 + 0i)`},
+               {`package b5; var _ = "foo"`, `"foo"`, `string`, `"foo"`},
+
+               {`package c0a; var _ = bool(false)`, `false`, `bool`, `false`},
+               {`package c0b; var _ = bool(false)`, `bool(false)`, `bool`, `false`},
+               {`package c0c; type T bool; var _ = T(false)`, `T(false)`, `c0c.T`, `false`},
+
+               {`package c1a; var _ = int(0)`, `0`, `int`, `0`},
+               {`package c1b; var _ = int(0)`, `int(0)`, `int`, `0`},
+               {`package c1c; type T int; var _ = T(0)`, `T(0)`, `c1c.T`, `0`},
+
+               {`package c2a; var _ = rune('A')`, `'A'`, `rune`, `65`},
+               {`package c2b; var _ = rune('A')`, `rune('A')`, `rune`, `65`},
+               {`package c2c; type T rune; var _ = T('A')`, `T('A')`, `c2c.T`, `65`},
+
+               {`package c3a; var _ = float32(0.)`, `0.`, `float32`, `0`},
+               {`package c3b; var _ = float32(0.)`, `float32(0.)`, `float32`, `0`},
+               {`package c3c; type T float32; var _ = T(0.)`, `T(0.)`, `c3c.T`, `0`},
+
+               {`package c4a; var _ = complex64(0i)`, `0i`, `complex64`, `(0 + 0i)`},
+               {`package c4b; var _ = complex64(0i)`, `complex64(0i)`, `complex64`, `(0 + 0i)`},
+               {`package c4c; type T complex64; var _ = T(0i)`, `T(0i)`, `c4c.T`, `(0 + 0i)`},
+
+               {`package c5a; var _ = string("foo")`, `"foo"`, `string`, `"foo"`},
+               {`package c5b; var _ = string("foo")`, `string("foo")`, `string`, `"foo"`},
+               {`package c5c; type T string; var _ = T("foo")`, `T("foo")`, `c5c.T`, `"foo"`},
+               {`package c5d; var _ = string(65)`, `65`, `untyped int`, `65`},
+               {`package c5e; var _ = string('A')`, `'A'`, `untyped rune`, `65`},
+               {`package c5f; type T string; var _ = T('A')`, `'A'`, `untyped rune`, `65`},
+               {`package c5g; var s uint; var _ = string(1 << s)`, `1 << s`, `untyped int`, ``},
+
+               {`package d0; var _ = []byte("foo")`, `"foo"`, `string`, `"foo"`},
+               {`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`},
+               {`package d2; var _ = []byte(string("foo"))`, `string("foo")`, `string`, `"foo"`},
+               {`package d3; type T []byte; var _ = T("foo")`, `"foo"`, `string`, `"foo"`},
+
+               {`package e0; const _ = float32( 1e-200)`, `float32(1e-200)`, `float32`, `0`},
+               {`package e1; const _ = float32(-1e-200)`, `float32(-1e-200)`, `float32`, `0`},
+               {`package e2; const _ = float64( 1e-2000)`, `float64(1e-2000)`, `float64`, `0`},
+               {`package e3; const _ = float64(-1e-2000)`, `float64(-1e-2000)`, `float64`, `0`},
+               {`package e4; const _ = complex64( 1e-200)`, `complex64(1e-200)`, `complex64`, `(0 + 0i)`},
+               {`package e5; const _ = complex64(-1e-200)`, `complex64(-1e-200)`, `complex64`, `(0 + 0i)`},
+               {`package e6; const _ = complex128( 1e-2000)`, `complex128(1e-2000)`, `complex128`, `(0 + 0i)`},
+               {`package e7; const _ = complex128(-1e-2000)`, `complex128(-1e-2000)`, `complex128`, `(0 + 0i)`},
+
+               {`package f0 ; var _ float32 =  1e-200`, `1e-200`, `float32`, `0`},
+               {`package f1 ; var _ float32 = -1e-200`, `-1e-200`, `float32`, `0`},
+               {`package f2a; var _ float64 =  1e-2000`, `1e-2000`, `float64`, `0`},
+               {`package f3a; var _ float64 = -1e-2000`, `-1e-2000`, `float64`, `0`},
+               {`package f2b; var _         =  1e-2000`, `1e-2000`, `float64`, `0`},
+               {`package f3b; var _         = -1e-2000`, `-1e-2000`, `float64`, `0`},
+               {`package f4 ; var _ complex64  =  1e-200 `, `1e-200`, `complex64`, `(0 + 0i)`},
+               {`package f5 ; var _ complex64  = -1e-200 `, `-1e-200`, `complex64`, `(0 + 0i)`},
+               {`package f6a; var _ complex128 =  1e-2000i`, `1e-2000i`, `complex128`, `(0 + 0i)`},
+               {`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `(0 + 0i)`},
+               {`package f6b; var _            =  1e-2000i`, `1e-2000i`, `complex128`, `(0 + 0i)`},
+               {`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
+       }
+
+       for _, test := range tests {
+               info := Info{
+                       Types: make(map[syntax.Expr]TypeAndValue),
+               }
+               name := mustTypecheck(t, "ValuesInfo", test.src, &info)
+
+               // look for expression
+               var expr syntax.Expr
+               for e := range info.Types {
+                       if ExprString(e) == test.expr {
+                               expr = e
+                               break
+                       }
+               }
+               if expr == nil {
+                       t.Errorf("package %s: no expression found for %s", name, test.expr)
+                       continue
+               }
+               tv := info.Types[expr]
+
+               // check that type is correct
+               if got := tv.Type.String(); got != test.typ {
+                       t.Errorf("package %s: got type %s; want %s", name, got, test.typ)
+                       continue
+               }
+
+               // if we have a constant, check that value is correct
+               if tv.Value != nil {
+                       if got := tv.Value.ExactString(); got != test.val {
+                               t.Errorf("package %s: got value %s; want %s", name, got, test.val)
+                       }
+               } else {
+                       if test.val != "" {
+                               t.Errorf("package %s: no constant found; want %s", name, test.val)
+                       }
+               }
+       }
+}
+
+func TestTypesInfo(t *testing.T) {
+       var tests = []struct {
+               src  string
+               expr string // expression
+               typ  string // value type
+       }{
+               // single-valued expressions of untyped constants
+               {`package b0; var x interface{} = false`, `false`, `bool`},
+               {`package b1; var x interface{} = 0`, `0`, `int`},
+               {`package b2; var x interface{} = 0.`, `0.`, `float64`},
+               {`package b3; var x interface{} = 0i`, `0i`, `complex128`},
+               {`package b4; var x interface{} = "foo"`, `"foo"`, `string`},
+
+               // comma-ok expressions
+               {`package p0; var x interface{}; var _, _ = x.(int)`,
+                       `x.(int)`,
+                       `(int, bool)`,
+               },
+               {`package p1; var x interface{}; func _() { _, _ = x.(int) }`,
+                       `x.(int)`,
+                       `(int, bool)`,
+               },
+               {`package p2a; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`,
+                       `m["foo"]`,
+                       `(complex128, p2a.mybool)`,
+               },
+               {`package p2b; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`,
+                       `m["foo"]`,
+                       `(complex128, bool)`,
+               },
+               {`package p3; var c chan string; var _, _ = <-c`,
+                       `<-c`,
+                       `(string, bool)`,
+               },
+
+               // issue 6796
+               {`package issue6796_a; var x interface{}; var _, _ = (x.(int))`,
+                       `x.(int)`,
+                       `(int, bool)`,
+               },
+               {`package issue6796_b; var c chan string; var _, _ = (<-c)`,
+                       `(<-c)`,
+                       `(string, bool)`,
+               },
+               {`package issue6796_c; var c chan string; var _, _ = (<-c)`,
+                       `<-c`,
+                       `(string, bool)`,
+               },
+               {`package issue6796_d; var c chan string; var _, _ = ((<-c))`,
+                       `(<-c)`,
+                       `(string, bool)`,
+               },
+               {`package issue6796_e; func f(c chan string) { _, _ = ((<-c)) }`,
+                       `(<-c)`,
+                       `(string, bool)`,
+               },
+
+               // issue 7060
+               {`package issue7060_a; var ( m map[int]string; x, ok = m[0] )`,
+                       `m[0]`,
+                       `(string, bool)`,
+               },
+               {`package issue7060_b; var ( m map[int]string; x, ok interface{} = m[0] )`,
+                       `m[0]`,
+                       `(string, bool)`,
+               },
+               {`package issue7060_c; func f(x interface{}, ok bool, m map[int]string) { x, ok = m[0] }`,
+                       `m[0]`,
+                       `(string, bool)`,
+               },
+               {`package issue7060_d; var ( ch chan string; x, ok = <-ch )`,
+                       `<-ch`,
+                       `(string, bool)`,
+               },
+               {`package issue7060_e; var ( ch chan string; x, ok interface{} = <-ch )`,
+                       `<-ch`,
+                       `(string, bool)`,
+               },
+               {`package issue7060_f; func f(x interface{}, ok bool, ch chan string) { x, ok = <-ch }`,
+                       `<-ch`,
+                       `(string, bool)`,
+               },
+
+               // issue 28277
+               {`package issue28277_a; func f(...int)`,
+                       `...int`,
+                       `[]int`,
+               },
+               {`package issue28277_b; func f(a, b int, c ...[]struct{})`,
+                       `...[]struct{}`,
+                       `[][]struct{}`,
+               },
+
+               // tests for broken code that doesn't parse or type-check
+               {`package x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
+               {`package x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
+               {`package x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a, f: b,}}`, `b`, `string`},
+               {`package x3; var x = panic("");`, `panic`, `func(interface{})`},
+               {`package x4; func _() { panic("") }`, `panic`, `func(interface{})`},
+               {`package x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
+
+               // parameterized functions
+               {`package p0; func f[T any](T); var _ = f[int]`, `f`, `func[T₁ any](T₁)`},
+               {`package p1; func f[T any](T); var _ = f[int]`, `f[int]`, `func(int)`},
+               {`package p2; func f[T any](T); var _ = f(42)`, `f`, `func[T₁ any](T₁)`},
+               {`package p2; func f[T any](T); var _ = f(42)`, `f(42)`, `()`},
+
+               // type parameters
+               {`package t0; type t[] int; var _ t`, `t`, `t0.t`}, // t[] is a syntax error that is ignored in this test in favor of t
+               {`package t1; type t[P any] int; var _ t[int]`, `t`, `t1.t[P₁ any]`},
+               {`package t2; type t[P interface{}] int; var _ t[int]`, `t`, `t2.t[P₁ interface{}]`},
+               {`package t3; type t[P, Q interface{}] int; var _ t[int, int]`, `t`, `t3.t[P₁, Q₂ interface{}]`},
+               {`package t4; type t[P, Q interface{ m() }] int; var _ t[int, int]`, `t`, `t4.t[P₁, Q₂ interface{m()}]`},
+
+               // instantiated types must be sanitized
+               {`package g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `g0.t[int]`},
+       }
+
+       for _, test := range tests {
+               info := Info{Types: make(map[syntax.Expr]TypeAndValue)}
+               name, _ := mayTypecheck(t, "TypesInfo", test.src, &info)
+
+               // look for expression type
+               var typ Type
+               for e, tv := range info.Types {
+                       if ExprString(e) == test.expr {
+                               typ = tv.Type
+                               break
+                       }
+               }
+               if typ == nil {
+                       t.Errorf("package %s: no type found for %s", name, test.expr)
+                       continue
+               }
+
+               // check that type is correct
+               if got := typ.String(); got != test.typ {
+                       t.Errorf("package %s: got %s; want %s", name, got, test.typ)
+               }
+       }
+}
+
+func TestInferredInfo(t *testing.T) {
+       var tests = []struct {
+               src   string
+               fun   string
+               targs []string
+               sig   string
+       }{
+               {`package p0; func f[T any](T); func _() { f(42) }`,
+                       `f`,
+                       []string{`int`},
+                       `func(int)`,
+               },
+               {`package p1; func f[T any](T) T; func _() { f('@') }`,
+                       `f`,
+                       []string{`rune`},
+                       `func(rune) rune`,
+               },
+               {`package p2; func f[T any](...T) T; func _() { f(0i) }`,
+                       `f`,
+                       []string{`complex128`},
+                       `func(...complex128) complex128`,
+               },
+               {`package p3; func f[A, B, C any](A, *B, []C); func _() { f(1.2, new(string), []byte{}) }`,
+                       `f`,
+                       []string{`float64`, `string`, `byte`},
+                       `func(float64, *string, []byte)`,
+               },
+               {`package p4; func f[A, B any](A, *B, ...[]B); func _() { f(1.2, new(byte)) }`,
+                       `f`,
+                       []string{`float64`, `byte`},
+                       `func(float64, *byte, ...[]byte)`,
+               },
+
+               // we don't know how to translate these but we can type-check them
+               {`package q0; type T struct{}; func (T) m[P any](P); func _(x T) { x.m(42) }`,
+                       `x.m`,
+                       []string{`int`},
+                       `func(int)`,
+               },
+               {`package q1; type T struct{}; func (T) m[P any](P) P; func _(x T) { x.m(42) }`,
+                       `x.m`,
+                       []string{`int`},
+                       `func(int) int`,
+               },
+               {`package q2; type T struct{}; func (T) m[P any](...P) P; func _(x T) { x.m(42) }`,
+                       `x.m`,
+                       []string{`int`},
+                       `func(...int) int`,
+               },
+               {`package q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C); func _(x T) { x.m(1.2, new(string), []byte{}) }`,
+                       `x.m`,
+                       []string{`float64`, `string`, `byte`},
+                       `func(float64, *string, []byte)`,
+               },
+               {`package q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B); func _(x T) { x.m(1.2, new(byte)) }`,
+                       `x.m`,
+                       []string{`float64`, `byte`},
+                       `func(float64, *byte, ...[]byte)`,
+               },
+
+               {`package r0; type T[P any] struct{}; func (_ T[P]) m[Q any](Q); func _[P any](x T[P]) { x.m(42) }`,
+                       `x.m`,
+                       []string{`int`},
+                       `func(int)`,
+               },
+               // TODO(gri) record method type parameters in syntax.FuncType so we can check this
+               // {`package r1; type T interface{ m[P any](P) }; func _(x T) { x.m(4.2) }`,
+               //      `x.m`,
+               //      []string{`float64`},
+               //      `func(float64)`,
+               // },
+
+               {`package s1; func f[T any, P interface{type *T}](x T); func _(x string) { f(x) }`,
+                       `f`,
+                       []string{`string`, `*string`},
+                       `func(x string)`,
+               },
+               {`package s2; func f[T any, P interface{type *T}](x []T); func _(x []int) { f(x) }`,
+                       `f`,
+                       []string{`int`, `*int`},
+                       `func(x []int)`,
+               },
+               {`package s3; type C[T any] interface{type chan<- T}; func f[T any, P C[T]](x []T); func _(x []int) { f(x) }`,
+                       `f`,
+                       []string{`int`, `chan<- int`},
+                       `func(x []int)`,
+               },
+               {`package s4; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T); func _(x []int) { f(x) }`,
+                       `f`,
+                       []string{`int`, `chan<- int`, `chan<- []*chan<- int`},
+                       `func(x []int)`,
+               },
+
+               {`package t1; func f[T any, P interface{type *T}]() T; func _() { _ = f[string] }`,
+                       `f`,
+                       []string{`string`, `*string`},
+                       `func() string`,
+               },
+               {`package t2; type C[T any] interface{type chan<- T}; func f[T any, P C[T]]() []T; func _() { _ = f[int] }`,
+                       `f`,
+                       []string{`int`, `chan<- int`},
+                       `func() []int`,
+               },
+               {`package t3; type C[T any] interface{type chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T; func _() { _ = f[int] }`,
+                       `f`,
+                       []string{`int`, `chan<- int`, `chan<- []*chan<- int`},
+                       `func() []int`,
+               },
+       }
+
+       for _, test := range tests {
+               info := Info{Inferred: make(map[syntax.Expr]Inferred)}
+               name, err := mayTypecheck(t, "InferredInfo", test.src, &info)
+               if err != nil {
+                       t.Errorf("package %s: %v", name, err)
+                       continue
+               }
+
+               // look for inferred type arguments and signature
+               var targs []Type
+               var sig *Signature
+               for call, inf := range info.Inferred {
+                       var fun syntax.Expr
+                       switch x := call.(type) {
+                       case *syntax.CallExpr:
+                               fun = x.Fun
+                       case *syntax.IndexExpr:
+                               fun = x.X
+                       default:
+                               panic(fmt.Sprintf("unexpected call expression type %T", call))
+                       }
+                       if ExprString(fun) == test.fun {
+                               targs = inf.Targs
+                               sig = inf.Sig
+                               break
+                       }
+               }
+               if targs == nil {
+                       t.Errorf("package %s: no inferred information found for %s", name, test.fun)
+                       continue
+               }
+
+               // check that type arguments are correct
+               if len(targs) != len(test.targs) {
+                       t.Errorf("package %s: got %d type arguments; want %d", name, len(targs), len(test.targs))
+                       continue
+               }
+               for i, targ := range targs {
+                       if got := targ.String(); got != test.targs[i] {
+                               t.Errorf("package %s, %d. type argument: got %s; want %s", name, i, got, test.targs[i])
+                               continue
+                       }
+               }
+
+               // check that signature is correct
+               if got := sig.String(); got != test.sig {
+                       t.Errorf("package %s: got %s; want %s", name, got, test.sig)
+               }
+       }
+}
+
+func TestDefsInfo(t *testing.T) {
+       var tests = []struct {
+               src  string
+               obj  string
+               want string
+       }{
+               {`package p0; const x = 42`, `x`, `const p0.x untyped int`},
+               {`package p1; const x int = 42`, `x`, `const p1.x int`},
+               {`package p2; var x int`, `x`, `var p2.x int`},
+               {`package p3; type x int`, `x`, `type p3.x int`},
+               {`package p4; func f()`, `f`, `func p4.f()`},
+
+               // generic types must be sanitized
+               // (need to use sufficiently nested types to provoke unexpanded types)
+               {`package g0; type t[P any] P; const x = t[int](42)`, `x`, `const g0.x g0.t[int]`},
+               {`package g1; type t[P any] P; var x = t[int](42)`, `x`, `var g1.x g1.t[int]`},
+               {`package g2; type t[P any] P; type x struct{ f t[int] }`, `x`, `type g2.x struct{f g2.t[int]}`},
+               {`package g3; type t[P any] P; func f(x struct{ f t[string] }); var g = f`, `g`, `var g3.g func(x struct{f g3.t[string]})`},
+       }
+
+       for _, test := range tests {
+               info := Info{
+                       Defs: make(map[*syntax.Name]Object),
+               }
+               name := mustTypecheck(t, "DefsInfo", test.src, &info)
+
+               // find object
+               var def Object
+               for id, obj := range info.Defs {
+                       if id.Value == test.obj {
+                               def = obj
+                               break
+                       }
+               }
+               if def == nil {
+                       t.Errorf("package %s: %s not found", name, test.obj)
+                       continue
+               }
+
+               if got := def.String(); got != test.want {
+                       t.Errorf("package %s: got %s; want %s", name, got, test.want)
+               }
+       }
+}
+
+func TestUsesInfo(t *testing.T) {
+       var tests = []struct {
+               src  string
+               obj  string
+               want string
+       }{
+               {`package p0; func _() { _ = x }; const x = 42`, `x`, `const p0.x untyped int`},
+               {`package p1; func _() { _ = x }; const x int = 42`, `x`, `const p1.x int`},
+               {`package p2; func _() { _ = x }; var x int`, `x`, `var p2.x int`},
+               {`package p3; func _() { type _ x }; type x int`, `x`, `type p3.x int`},
+               {`package p4; func _() { _ = f }; func f()`, `f`, `func p4.f()`},
+
+               // generic types must be sanitized
+               // (need to use sufficiently nested types to provoke unexpanded types)
+               {`package g0; func _() { _ = x }; type t[P any] P; const x = t[int](42)`, `x`, `const g0.x g0.t[int]`},
+               {`package g1; func _() { _ = x }; type t[P any] P; var x = t[int](42)`, `x`, `var g1.x g1.t[int]`},
+               {`package g2; func _() { type _ x }; type t[P any] P; type x struct{ f t[int] }`, `x`, `type g2.x struct{f g2.t[int]}`},
+               {`package g3; func _() { _ = f }; type t[P any] P; func f(x struct{ f t[string] })`, `f`, `func g3.f(x struct{f g3.t[string]})`},
+       }
+
+       for _, test := range tests {
+               info := Info{
+                       Uses: make(map[*syntax.Name]Object),
+               }
+               name := mustTypecheck(t, "UsesInfo", test.src, &info)
+
+               // find object
+               var use Object
+               for id, obj := range info.Uses {
+                       if id.Value == test.obj {
+                               use = obj
+                               break
+                       }
+               }
+               if use == nil {
+                       t.Errorf("package %s: %s not found", name, test.obj)
+                       continue
+               }
+
+               if got := use.String(); got != test.want {
+                       t.Errorf("package %s: got %s; want %s", name, got, test.want)
+               }
+       }
+}
+
+func TestImplicitsInfo(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       var tests = []struct {
+               src  string
+               want string
+       }{
+               {`package p2; import . "fmt"; var _ = Println`, ""},           // no Implicits entry
+               {`package p0; import local "fmt"; var _ = local.Println`, ""}, // no Implicits entry
+               {`package p1; import "fmt"; var _ = fmt.Println`, "importSpec: package fmt"},
+
+               {`package p3; func f(x interface{}) { switch x.(type) { case int: } }`, ""}, // no Implicits entry
+               {`package p4; func f(x interface{}) { switch t := x.(type) { case int: _ = t } }`, "caseClause: var t int"},
+               {`package p5; func f(x interface{}) { switch t := x.(type) { case int, uint: _ = t } }`, "caseClause: var t interface{}"},
+               {`package p6; func f(x interface{}) { switch t := x.(type) { default: _ = t } }`, "caseClause: var t interface{}"},
+
+               {`package p7; func f(x int) {}`, ""}, // no Implicits entry
+               {`package p8; func f(int) {}`, "field: var  int"},
+               {`package p9; func f() (complex64) { return 0 }`, "field: var  complex64"},
+               {`package p10; type T struct{}; func (*T) f() {}`, "field: var  *p10.T"},
+       }
+
+       for _, test := range tests {
+               info := Info{
+                       Implicits: make(map[syntax.Node]Object),
+               }
+               name := mustTypecheck(t, "ImplicitsInfo", test.src, &info)
+
+               // the test cases expect at most one Implicits entry
+               if len(info.Implicits) > 1 {
+                       t.Errorf("package %s: %d Implicits entries found", name, len(info.Implicits))
+                       continue
+               }
+
+               // extract Implicits entry, if any
+               var got string
+               for n, obj := range info.Implicits {
+                       switch x := n.(type) {
+                       case *syntax.ImportDecl:
+                               got = "importSpec"
+                       case *syntax.CaseClause:
+                               got = "caseClause"
+                       case *syntax.Field:
+                               got = "field"
+                       default:
+                               t.Fatalf("package %s: unexpected %T", name, x)
+                       }
+                       got += ": " + obj.String()
+               }
+
+               // verify entry
+               if got != test.want {
+                       t.Errorf("package %s: got %q; want %q", name, got, test.want)
+               }
+       }
+}
+
+func predString(tv TypeAndValue) string {
+       var buf bytes.Buffer
+       pred := func(b bool, s string) {
+               if b {
+                       if buf.Len() > 0 {
+                               buf.WriteString(", ")
+                       }
+                       buf.WriteString(s)
+               }
+       }
+
+       pred(tv.IsVoid(), "void")
+       pred(tv.IsType(), "type")
+       pred(tv.IsBuiltin(), "builtin")
+       pred(tv.IsValue() && tv.Value != nil, "const")
+       pred(tv.IsValue() && tv.Value == nil, "value")
+       pred(tv.IsNil(), "nil")
+       pred(tv.Addressable(), "addressable")
+       pred(tv.Assignable(), "assignable")
+       pred(tv.HasOk(), "hasOk")
+
+       if buf.Len() == 0 {
+               return "invalid"
+       }
+       return buf.String()
+}
+
+func TestPredicatesInfo(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       var tests = []struct {
+               src  string
+               expr string
+               pred string
+       }{
+               // void
+               {`package n0; func f() { f() }`, `f()`, `void`},
+
+               // types
+               {`package t0; type _ int`, `int`, `type`},
+               {`package t1; type _ []int`, `[]int`, `type`},
+               {`package t2; type _ func()`, `func()`, `type`},
+               {`package t3; type _ func(int)`, `int`, `type`},
+               {`package t3; type _ func(...int)`, `...int`, `type`},
+
+               // built-ins
+               {`package b0; var _ = len("")`, `len`, `builtin`},
+               {`package b1; var _ = (len)("")`, `(len)`, `builtin`},
+
+               // constants
+               {`package c0; var _ = 42`, `42`, `const`},
+               {`package c1; var _ = "foo" + "bar"`, `"foo" + "bar"`, `const`},
+               {`package c2; const (i = 1i; _ = i)`, `i`, `const`},
+
+               // values
+               {`package v0; var (a, b int; _ = a + b)`, `a + b`, `value`},
+               {`package v1; var _ = &[]int{1}`, `[]int{…}`, `value`},
+               {`package v2; var _ = func(){}`, `func() {}`, `value`},
+               {`package v4; func f() { _ = f }`, `f`, `value`},
+               {`package v3; var _ *int = nil`, `nil`, `value, nil`},
+               {`package v3; var _ *int = (nil)`, `(nil)`, `value, nil`},
+
+               // addressable (and thus assignable) operands
+               {`package a0; var (x int; _ = x)`, `x`, `value, addressable, assignable`},
+               {`package a1; var (p *int; _ = *p)`, `*p`, `value, addressable, assignable`},
+               {`package a2; var (s []int; _ = s[0])`, `s[0]`, `value, addressable, assignable`},
+               {`package a3; var (s struct{f int}; _ = s.f)`, `s.f`, `value, addressable, assignable`},
+               {`package a4; var (a [10]int; _ = a[0])`, `a[0]`, `value, addressable, assignable`},
+               {`package a5; func _(x int) { _ = x }`, `x`, `value, addressable, assignable`},
+               {`package a6; func _()(x int) { _ = x; return }`, `x`, `value, addressable, assignable`},
+               {`package a7; type T int; func (x T) _() { _ = x }`, `x`, `value, addressable, assignable`},
+               // composite literals are not addressable
+
+               // assignable but not addressable values
+               {`package s0; var (m map[int]int; _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
+               {`package s1; var (m map[int]int; _, _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
+
+               // hasOk expressions
+               {`package k0; var (ch chan int; _ = <-ch)`, `<-ch`, `value, hasOk`},
+               {`package k1; var (ch chan int; _, _ = <-ch)`, `<-ch`, `value, hasOk`},
+
+               // missing entries
+               // - package names are collected in the Uses map
+               // - identifiers being declared are collected in the Defs map
+               {`package m0; import "os"; func _() { _ = os.Stdout }`, `os`, `<missing>`},
+               {`package m1; import p "os"; func _() { _ = p.Stdout }`, `p`, `<missing>`},
+               {`package m2; const c = 0`, `c`, `<missing>`},
+               {`package m3; type T int`, `T`, `<missing>`},
+               {`package m4; var v int`, `v`, `<missing>`},
+               {`package m5; func f() {}`, `f`, `<missing>`},
+               {`package m6; func _(x int) {}`, `x`, `<missing>`},
+               {`package m6; func _()(x int) { return }`, `x`, `<missing>`},
+               {`package m6; type T int; func (x T) _() {}`, `x`, `<missing>`},
+       }
+
+       for _, test := range tests {
+               info := Info{Types: make(map[syntax.Expr]TypeAndValue)}
+               name := mustTypecheck(t, "PredicatesInfo", test.src, &info)
+
+               // look for expression predicates
+               got := "<missing>"
+               for e, tv := range info.Types {
+                       //println(name, ExprString(e))
+                       if ExprString(e) == test.expr {
+                               got = predString(tv)
+                               break
+                       }
+               }
+
+               if got != test.pred {
+                       t.Errorf("package %s: got %s; want %s", name, got, test.pred)
+               }
+       }
+}
+
+func TestScopesInfo(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       var tests = []struct {
+               src    string
+               scopes []string // list of scope descriptors of the form kind:varlist
+       }{
+               {`package p0`, []string{
+                       "file:",
+               }},
+               {`package p1; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{
+                       "file:fmt m",
+               }},
+               {`package p2; func _() {}`, []string{
+                       "file:", "func:",
+               }},
+               {`package p3; func _(x, y int) {}`, []string{
+                       "file:", "func:x y",
+               }},
+               {`package p4; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{
+                       "file:", "func:x y z", // redeclaration of x
+               }},
+               {`package p5; func _(x, y int) (u, _ int) { return }`, []string{
+                       "file:", "func:u x y",
+               }},
+               {`package p6; func _() { { var x int; _ = x } }`, []string{
+                       "file:", "func:", "block:x",
+               }},
+               {`package p7; func _() { if true {} }`, []string{
+                       "file:", "func:", "if:", "block:",
+               }},
+               {`package p8; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{
+                       "file:", "func:", "if:x", "block:y",
+               }},
+               {`package p9; func _() { switch x := 0; x {} }`, []string{
+                       "file:", "func:", "switch:x",
+               }},
+               {`package p10; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{
+                       "file:", "func:", "switch:x", "case:y", "case:",
+               }},
+               {`package p11; func _(t interface{}) { switch t.(type) {} }`, []string{
+                       "file:", "func:t", "switch:",
+               }},
+               {`package p12; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{
+                       "file:", "func:t", "switch:t",
+               }},
+               {`package p13; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{
+                       "file:", "func:t", "switch:", "case:x", // x implicitly declared
+               }},
+               {`package p14; func _() { select{} }`, []string{
+                       "file:", "func:",
+               }},
+               {`package p15; func _(c chan int) { select{ case <-c: } }`, []string{
+                       "file:", "func:c", "select:",
+               }},
+               {`package p16; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{
+                       "file:", "func:c", "select:i x",
+               }},
+               {`package p17; func _() { for{} }`, []string{
+                       "file:", "func:", "for:", "block:",
+               }},
+               {`package p18; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{
+                       "file:", "func:n", "for:i", "block:",
+               }},
+               {`package p19; func _(a []int) { for i := range a { _ = i} }`, []string{
+                       "file:", "func:a", "for:i", "block:",
+               }},
+               {`package p20; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{
+                       "file:", "func:a", "for:i x", "block:",
+               }},
+       }
+
+       for _, test := range tests {
+               info := Info{Scopes: make(map[syntax.Node]*Scope)}
+               name := mustTypecheck(t, "ScopesInfo", test.src, &info)
+
+               // number of scopes must match
+               if len(info.Scopes) != len(test.scopes) {
+                       t.Errorf("package %s: got %d scopes; want %d", name, len(info.Scopes), len(test.scopes))
+               }
+
+               // scope descriptions must match
+               for node, scope := range info.Scopes {
+                       var kind string
+                       switch node.(type) {
+                       case *syntax.File:
+                               kind = "file"
+                       case *syntax.FuncType:
+                               kind = "func"
+                       case *syntax.BlockStmt:
+                               kind = "block"
+                       case *syntax.IfStmt:
+                               kind = "if"
+                       case *syntax.SwitchStmt:
+                               kind = "switch"
+                       case *syntax.SelectStmt:
+                               kind = "select"
+                       case *syntax.CaseClause:
+                               kind = "case"
+                       case *syntax.CommClause:
+                               kind = "comm"
+                       case *syntax.ForStmt:
+                               kind = "for"
+                       default:
+                               kind = fmt.Sprintf("%T", node)
+                       }
+
+                       // look for matching scope description
+                       desc := kind + ":" + strings.Join(scope.Names(), " ")
+                       found := false
+                       for _, d := range test.scopes {
+                               if desc == d {
+                                       found = true
+                                       break
+                               }
+                       }
+                       if !found {
+                               t.Errorf("package %s: no matching scope found for %s", name, desc)
+                       }
+               }
+       }
+}
+
+func TestInitOrderInfo(t *testing.T) {
+       var tests = []struct {
+               src   string
+               inits []string
+       }{
+               {`package p0; var (x = 1; y = x)`, []string{
+                       "x = 1", "y = x",
+               }},
+               {`package p1; var (a = 1; b = 2; c = 3)`, []string{
+                       "a = 1", "b = 2", "c = 3",
+               }},
+               {`package p2; var (a, b, c = 1, 2, 3)`, []string{
+                       "a = 1", "b = 2", "c = 3",
+               }},
+               {`package p3; var _ = f(); func f() int { return 1 }`, []string{
+                       "_ = f()", // blank var
+               }},
+               {`package p4; var (a = 0; x = y; y = z; z = 0)`, []string{
+                       "a = 0", "z = 0", "y = z", "x = y",
+               }},
+               {`package p5; var (a, _ = m[0]; m map[int]string)`, []string{
+                       "a, _ = m[0]", // blank var
+               }},
+               {`package p6; var a, b = f(); func f() (_, _ int) { return z, z }; var z = 0`, []string{
+                       "z = 0", "a, b = f()",
+               }},
+               {`package p7; var (a = func() int { return b }(); b = 1)`, []string{
+                       "b = 1", "a = func() int {…}()",
+               }},
+               {`package p8; var (a, b = func() (_, _ int) { return c, c }(); c = 1)`, []string{
+                       "c = 1", "a, b = func() (_, _ int) {…}()",
+               }},
+               {`package p9; type T struct{}; func (T) m() int { _ = y; return 0 }; var x, y = T.m, 1`, []string{
+                       "y = 1", "x = T.m",
+               }},
+               {`package p10; var (d = c + b; a = 0; b = 0; c = 0)`, []string{
+                       "a = 0", "b = 0", "c = 0", "d = c + b",
+               }},
+               {`package p11; var (a = e + c; b = d + c; c = 0; d = 0; e = 0)`, []string{
+                       "c = 0", "d = 0", "b = d + c", "e = 0", "a = e + c",
+               }},
+               // emit an initializer for n:1 initializations only once (not for each node
+               // on the lhs which may appear in different order in the dependency graph)
+               {`package p12; var (a = x; b = 0; x, y = m[0]; m map[int]int)`, []string{
+                       "b = 0", "x, y = m[0]", "a = x",
+               }},
+               // test case from spec section on package initialization
+               {`package p12
+
+               var (
+                       a = c + b
+                       b = f()
+                       c = f()
+                       d = 3
+               )
+
+               func f() int {
+                       d++
+                       return d
+               }`, []string{
+                       "d = 3", "b = f()", "c = f()", "a = c + b",
+               }},
+               // test case for issue 7131
+               {`package main
+
+               var counter int
+               func next() int { counter++; return counter }
+
+               var _ = makeOrder()
+               func makeOrder() []int { return []int{f, b, d, e, c, a} }
+
+               var a       = next()
+               var b, c    = next(), next()
+               var d, e, f = next(), next(), next()
+               `, []string{
+                       "a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()",
+               }},
+               // test case for issue 10709
+               {`package p13
+
+               var (
+                   v = t.m()
+                   t = makeT(0)
+               )
+
+               type T struct{}
+
+               func (T) m() int { return 0 }
+
+               func makeT(n int) T {
+                   if n > 0 {
+                       return makeT(n-1)
+                   }
+                   return T{}
+               }`, []string{
+                       "t = makeT(0)", "v = t.m()",
+               }},
+               // test case for issue 10709: same as test before, but variable decls swapped
+               {`package p14
+
+               var (
+                   t = makeT(0)
+                   v = t.m()
+               )
+
+               type T struct{}
+
+               func (T) m() int { return 0 }
+
+               func makeT(n int) T {
+                   if n > 0 {
+                       return makeT(n-1)
+                   }
+                   return T{}
+               }`, []string{
+                       "t = makeT(0)", "v = t.m()",
+               }},
+               // another candidate possibly causing problems with issue 10709
+               {`package p15
+
+               var y1 = f1()
+
+               func f1() int { return g1() }
+               func g1() int { f1(); return x1 }
+
+               var x1 = 0
+
+               var y2 = f2()
+
+               func f2() int { return g2() }
+               func g2() int { return x2 }
+
+               var x2 = 0`, []string{
+                       "x1 = 0", "y1 = f1()", "x2 = 0", "y2 = f2()",
+               }},
+       }
+
+       for _, test := range tests {
+               info := Info{}
+               name := mustTypecheck(t, "InitOrderInfo", test.src, &info)
+
+               // number of initializers must match
+               if len(info.InitOrder) != len(test.inits) {
+                       t.Errorf("package %s: got %d initializers; want %d", name, len(info.InitOrder), len(test.inits))
+                       continue
+               }
+
+               // initializers must match
+               for i, want := range test.inits {
+                       got := info.InitOrder[i].String()
+                       if got != want {
+                               t.Errorf("package %s, init %d: got %s; want %s", name, i, got, want)
+                               continue
+                       }
+               }
+       }
+}
+
+func TestMultiFileInitOrder(t *testing.T) {
+       mustParse := func(src string) *syntax.File {
+               f, err := parseSrc("main", src)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               return f
+       }
+
+       fileA := mustParse(`package main; var a = 1`)
+       fileB := mustParse(`package main; var b = 2`)
+
+       // The initialization order must not depend on the parse
+       // order of the files, only on the presentation order to
+       // the type-checker.
+       for _, test := range []struct {
+               files []*syntax.File
+               want  string
+       }{
+               {[]*syntax.File{fileA, fileB}, "[a = 1 b = 2]"},
+               {[]*syntax.File{fileB, fileA}, "[b = 2 a = 1]"},
+       } {
+               var info Info
+               if _, err := new(Config).Check("main", test.files, &info); err != nil {
+                       t.Fatal(err)
+               }
+               if got := fmt.Sprint(info.InitOrder); got != test.want {
+                       t.Fatalf("got %s; want %s", got, test.want)
+               }
+       }
+}
+
+func TestFiles(t *testing.T) {
+       var sources = []string{
+               "package p; type T struct{}; func (T) m1() {}",
+               "package p; func (T) m2() {}; var x interface{ m1(); m2() } = T{}",
+               "package p; func (T) m3() {}; var y interface{ m1(); m2(); m3() } = T{}",
+               "package p",
+       }
+
+       var conf Config
+       pkg := NewPackage("p", "p")
+       var info Info
+       check := NewChecker(&conf, pkg, &info)
+
+       for i, src := range sources {
+               filename := fmt.Sprintf("sources%d", i)
+               f, err := parseSrc(filename, src)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if err := check.Files([]*syntax.File{f}); err != nil {
+                       t.Error(err)
+               }
+       }
+
+       // check InitOrder is [x y]
+       var vars []string
+       for _, init := range info.InitOrder {
+               for _, v := range init.Lhs {
+                       vars = append(vars, v.Name())
+               }
+       }
+       if got, want := fmt.Sprint(vars), "[x y]"; got != want {
+               t.Errorf("InitOrder == %s, want %s", got, want)
+       }
+}
+
+type testImporter map[string]*Package
+
+func (m testImporter) Import(path string) (*Package, error) {
+       if pkg := m[path]; pkg != nil {
+               return pkg, nil
+       }
+       return nil, fmt.Errorf("package %q not found", path)
+}
+
+func TestSelection(t *testing.T) {
+       t.Skip("requires fixes around source positions")
+
+       selections := make(map[*syntax.SelectorExpr]*Selection)
+
+       imports := make(testImporter)
+       conf := Config{Importer: imports}
+       makePkg := func(path, src string) {
+               f, err := parseSrc(path+".go", src)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               pkg, err := conf.Check(path, []*syntax.File{f}, &Info{Selections: selections})
+               if err != nil {
+                       t.Fatal(err)
+               }
+               imports[path] = pkg
+       }
+
+       const libSrc = `
+package lib
+type T float64
+const C T = 3
+var V T
+func F() {}
+func (T) M() {}
+`
+       const mainSrc = `
+package main
+import "lib"
+
+type A struct {
+       *B
+       C
+}
+
+type B struct {
+       b int
+}
+
+func (B) f(int)
+
+type C struct {
+       c int
+}
+
+func (C) g()
+func (*C) h()
+
+func main() {
+       // qualified identifiers
+       var _ lib.T
+        _ = lib.C
+        _ = lib.F
+        _ = lib.V
+       _ = lib.T.M
+
+       // fields
+       _ = A{}.B
+       _ = new(A).B
+
+       _ = A{}.C
+       _ = new(A).C
+
+       _ = A{}.b
+       _ = new(A).b
+
+       _ = A{}.c
+       _ = new(A).c
+
+       // methods
+        _ = A{}.f
+        _ = new(A).f
+        _ = A{}.g
+        _ = new(A).g
+        _ = new(A).h
+
+        _ = B{}.f
+        _ = new(B).f
+
+        _ = C{}.g
+        _ = new(C).g
+        _ = new(C).h
+
+       // method expressions
+        _ = A.f
+        _ = (*A).f
+        _ = B.f
+        _ = (*B).f
+}`
+
+       wantOut := map[string][2]string{
+               "lib.T.M": {"method expr (lib.T) M(lib.T)", ".[0]"},
+
+               "A{}.B":    {"field (main.A) B *main.B", ".[0]"},
+               "new(A).B": {"field (*main.A) B *main.B", "->[0]"},
+               "A{}.C":    {"field (main.A) C main.C", ".[1]"},
+               "new(A).C": {"field (*main.A) C main.C", "->[1]"},
+               "A{}.b":    {"field (main.A) b int", "->[0 0]"},
+               "new(A).b": {"field (*main.A) b int", "->[0 0]"},
+               "A{}.c":    {"field (main.A) c int", ".[1 0]"},
+               "new(A).c": {"field (*main.A) c int", "->[1 0]"},
+
+               "A{}.f":    {"method (main.A) f(int)", "->[0 0]"},
+               "new(A).f": {"method (*main.A) f(int)", "->[0 0]"},
+               "A{}.g":    {"method (main.A) g()", ".[1 0]"},
+               "new(A).g": {"method (*main.A) g()", "->[1 0]"},
+               "new(A).h": {"method (*main.A) h()", "->[1 1]"}, // TODO(gri) should this report .[1 1] ?
+               "B{}.f":    {"method (main.B) f(int)", ".[0]"},
+               "new(B).f": {"method (*main.B) f(int)", "->[0]"},
+               "C{}.g":    {"method (main.C) g()", ".[0]"},
+               "new(C).g": {"method (*main.C) g()", "->[0]"},
+               "new(C).h": {"method (*main.C) h()", "->[1]"}, // TODO(gri) should this report .[1] ?
+
+               "A.f":    {"method expr (main.A) f(main.A, int)", "->[0 0]"},
+               "(*A).f": {"method expr (*main.A) f(*main.A, int)", "->[0 0]"},
+               "B.f":    {"method expr (main.B) f(main.B, int)", ".[0]"},
+               "(*B).f": {"method expr (*main.B) f(*main.B, int)", "->[0]"},
+       }
+
+       makePkg("lib", libSrc)
+       makePkg("main", mainSrc)
+
+       for e, sel := range selections {
+               _ = sel.String() // assertion: must not panic
+
+               unimplemented()
+               _ = e
+               // start := fset.Position(e.Pos()).Offset
+               // end := fset.Position(e.End()).Offset
+               // syntax := mainSrc[start:end] // (all SelectorExprs are in main, not lib)
+
+               direct := "."
+               if sel.Indirect() {
+                       direct = "->"
+               }
+               got := [2]string{
+                       sel.String(),
+                       fmt.Sprintf("%s%v", direct, sel.Index()),
+               }
+               unimplemented()
+               _ = got
+               // want := wantOut[syntax]
+               // if want != got {
+               //      t.Errorf("%s: got %q; want %q", syntax, got, want)
+               // }
+               // delete(wantOut, syntax)
+
+               // We must explicitly assert properties of the
+               // Signature's receiver since it doesn't participate
+               // in Identical() or String().
+               sig, _ := sel.Type().(*Signature)
+               if sel.Kind() == MethodVal {
+                       got := sig.Recv().Type()
+                       want := sel.Recv()
+                       if !Identical(got, want) {
+                               unimplemented()
+                               // t.Errorf("%s: Recv() = %s, want %s", syntax, got, want)
+                       }
+               } else if sig != nil && sig.Recv() != nil {
+                       t.Errorf("%s: signature has receiver %s", sig, sig.Recv().Type())
+               }
+       }
+       // Assert that all wantOut entries were used exactly once.
+       for syntax := range wantOut {
+               t.Errorf("no syntax.Selection found with syntax %q", syntax)
+       }
+}
+
+func TestIssue8518(t *testing.T) {
+       imports := make(testImporter)
+       conf := Config{
+               Error:    func(err error) { t.Log(err) }, // don't exit after first error
+               Importer: imports,
+       }
+       makePkg := func(path, src string) {
+               f, err := parseSrc(path, src)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               pkg, _ := conf.Check(path, []*syntax.File{f}, nil) // errors logged via conf.Error
+               imports[path] = pkg
+       }
+
+       const libSrc = `
+package a
+import "missing"
+const C1 = foo
+const C2 = missing.C
+`
+
+       const mainSrc = `
+package main
+import "a"
+var _ = a.C1
+var _ = a.C2
+`
+
+       makePkg("a", libSrc)
+       makePkg("main", mainSrc) // don't crash when type-checking this package
+}
+
+func TestLookupFieldOrMethod(t *testing.T) {
+       // Test cases assume a lookup of the form a.f or x.f, where a stands for an
+       // addressable value, and x for a non-addressable value (even though a variable
+       // for ease of test case writing).
+       var tests = []struct {
+               src      string
+               found    bool
+               index    []int
+               indirect bool
+       }{
+               // field lookups
+               {"var x T; type T struct{}", false, nil, false},
+               {"var x T; type T struct{ f int }", true, []int{0}, false},
+               {"var x T; type T struct{ a, b, f, c int }", true, []int{2}, false},
+
+               // method lookups
+               {"var a T; type T struct{}; func (T) f() {}", true, []int{0}, false},
+               {"var a *T; type T struct{}; func (T) f() {}", true, []int{0}, true},
+               {"var a T; type T struct{}; func (*T) f() {}", true, []int{0}, false},
+               {"var a *T; type T struct{}; func (*T) f() {}", true, []int{0}, true}, // TODO(gri) should this report indirect = false?
+
+               // collisions
+               {"type ( E1 struct{ f int }; E2 struct{ f int }; x struct{ E1; *E2 })", false, []int{1, 0}, false},
+               {"type ( E1 struct{ f int }; E2 struct{}; x struct{ E1; *E2 }); func (E2) f() {}", false, []int{1, 0}, false},
+
+               // outside methodset
+               // (*T).f method exists, but value of type T is not addressable
+               {"var x T; type T struct{}; func (*T) f() {}", false, nil, true},
+       }
+
+       for _, test := range tests {
+               pkg, err := pkgFor("test", "package p;"+test.src, nil)
+               if err != nil {
+                       t.Errorf("%s: incorrect test case: %s", test.src, err)
+                       continue
+               }
+
+               obj := pkg.Scope().Lookup("a")
+               if obj == nil {
+                       if obj = pkg.Scope().Lookup("x"); obj == nil {
+                               t.Errorf("%s: incorrect test case - no object a or x", test.src)
+                               continue
+                       }
+               }
+
+               f, index, indirect := LookupFieldOrMethod(obj.Type(), obj.Name() == "a", pkg, "f")
+               if (f != nil) != test.found {
+                       if f == nil {
+                               t.Errorf("%s: got no object; want one", test.src)
+                       } else {
+                               t.Errorf("%s: got object = %v; want none", test.src, f)
+                       }
+               }
+               if !sameSlice(index, test.index) {
+                       t.Errorf("%s: got index = %v; want %v", test.src, index, test.index)
+               }
+               if indirect != test.indirect {
+                       t.Errorf("%s: got indirect = %v; want %v", test.src, indirect, test.indirect)
+               }
+       }
+}
+
+func sameSlice(a, b []int) bool {
+       if len(a) != len(b) {
+               return false
+       }
+       for i, x := range a {
+               if x != b[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+// TestScopeLookupParent ensures that (*Scope).LookupParent returns
+// the correct result at various positions within the source.
+func TestScopeLookupParent(t *testing.T) {
+       imports := make(testImporter)
+       conf := Config{Importer: imports}
+       var info Info
+       makePkg := func(path, src string) {
+               f, err := parseSrc(path, src)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               imports[path], err = conf.Check(path, []*syntax.File{f}, &info)
+               if err != nil {
+                       t.Fatal(err)
+               }
+       }
+
+       makePkg("lib", "package lib; var X int")
+       // Each /*name=kind:line*/ comment makes the test look up the
+       // name at that point and checks that it resolves to a decl of
+       // the specified kind and line number.  "undef" means undefined.
+       mainSrc := `
+/*lib=pkgname:5*/ /*X=var:1*/ /*Pi=const:8*/ /*T=typename:9*/ /*Y=var:10*/ /*F=func:12*/
+package main
+
+import "lib"
+import . "lib"
+
+const Pi = 3.1415
+type T struct{}
+var Y, _ = lib.X, X
+
+func F(){
+       const pi, e = 3.1415, /*pi=undef*/ 2.71828 /*pi=const:13*/ /*e=const:13*/
+       type /*t=undef*/ t /*t=typename:14*/ *t
+       print(Y) /*Y=var:10*/
+       x, Y := Y, /*x=undef*/ /*Y=var:10*/ Pi /*x=var:16*/ /*Y=var:16*/ ; _ = x; _ = Y
+       var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F
+
+       var a []int
+       for i, x := range /*i=undef*/ /*x=var:16*/ a /*i=var:20*/ /*x=var:20*/ { _ = i; _ = x }
+
+       var i interface{}
+       switch y := i.(type) { /*y=undef*/
+       case /*y=undef*/ int /*y=var:23*/ :
+       case float32, /*y=undef*/ float64 /*y=var:23*/ :
+       default /*y=var:23*/:
+               println(y)
+       }
+       /*y=undef*/
+
+        switch int := i.(type) {
+        case /*int=typename:0*/ int /*int=var:31*/ :
+               println(int)
+        default /*int=var:31*/ :
+        }
+}
+/*main=undef*/
+`
+
+       info.Uses = make(map[*syntax.Name]Object)
+       makePkg("main", mainSrc)
+       mainScope := imports["main"].Scope()
+
+       rx := regexp.MustCompile(`^/\*(\w*)=([\w:]*)\*/$`)
+
+       base := syntax.NewFileBase("main")
+       syntax.CommentsDo(strings.NewReader(mainSrc), func(line, col uint, text string) {
+               pos := syntax.MakePos(base, line, col)
+
+               // Syntax errors are not comments.
+               if text[0] != '/' {
+                       t.Errorf("%s: %s", pos, text)
+                       return
+               }
+
+               // Parse the assertion in the comment.
+               m := rx.FindStringSubmatch(text)
+               if m == nil {
+                       t.Errorf("%s: bad comment: %s", pos, text)
+                       return
+               }
+               name, want := m[1], m[2]
+
+               // Look up the name in the innermost enclosing scope.
+               inner := mainScope.Innermost(pos)
+               if inner == nil {
+                       t.Errorf("%s: at %s: can't find innermost scope", pos, text)
+                       return
+               }
+               got := "undef"
+               if _, obj := inner.LookupParent(name, pos); obj != nil {
+                       kind := strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types2."))
+                       got = fmt.Sprintf("%s:%d", kind, obj.Pos().Line())
+               }
+               if got != want {
+                       t.Errorf("%s: at %s: %s resolved to %s, want %s", pos, text, name, got, want)
+               }
+       })
+
+       // Check that for each referring identifier,
+       // a lookup of its name on the innermost
+       // enclosing scope returns the correct object.
+
+       for id, wantObj := range info.Uses {
+               inner := mainScope.Innermost(id.Pos())
+               if inner == nil {
+                       t.Errorf("%s: can't find innermost scope enclosing %q", id.Pos(), id.Value)
+                       continue
+               }
+
+               // Exclude selectors and qualified identifiers---lexical
+               // refs only.  (Ideally, we'd see if the AST parent is a
+               // SelectorExpr, but that requires PathEnclosingInterval
+               // from golang.org/x/tools/go/ast/astutil.)
+               if id.Value == "X" {
+                       continue
+               }
+
+               _, gotObj := inner.LookupParent(id.Value, id.Pos())
+               if gotObj != wantObj {
+                       t.Errorf("%s: got %v, want %v", id.Pos(), gotObj, wantObj)
+                       continue
+               }
+       }
+}
+
+func TestIdentical_issue15173(t *testing.T) {
+       // Identical should allow nil arguments and be symmetric.
+       for _, test := range []struct {
+               x, y Type
+               want bool
+       }{
+               {Typ[Int], Typ[Int], true},
+               {Typ[Int], nil, false},
+               {nil, Typ[Int], false},
+               {nil, nil, true},
+       } {
+               if got := Identical(test.x, test.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)
+       if err != nil {
+               t.Fatal(err)
+       }
+       conf := Config{
+               Error: func(err error) {}, // allow errors
+       }
+       info := &Info{
+               Types: make(map[syntax.Expr]TypeAndValue),
+       }
+       conf.Check("p", []*syntax.File{f}, info) // ignore result
+       for e, tv := range info.Types {
+               if _, ok := e.(*syntax.CallExpr); ok {
+                       if tv.Type != Typ[Int16] {
+                               t.Errorf("CallExpr has type %v, want int16", tv.Type)
+                       }
+                       return
+               }
+       }
+       t.Errorf("CallExpr has no type")
+}
+
+// TestCompositeLitTypes verifies that Info.Types registers the correct
+// types for composite literal expressions and composite literal type
+// expressions.
+func TestCompositeLitTypes(t *testing.T) {
+       for _, test := range []struct {
+               lit, typ string
+       }{
+               {`[16]byte{}`, `[16]byte`},
+               {`[...]byte{}`, `[0]byte`},                // test for issue #14092
+               {`[...]int{1, 2, 3}`, `[3]int`},           // test for issue #14092
+               {`[...]int{90: 0, 98: 1, 2}`, `[100]int`}, // test for issue #14092
+               {`[]int{}`, `[]int`},
+               {`map[string]bool{"foo": true}`, `map[string]bool`},
+               {`struct{}{}`, `struct{}`},
+               {`struct{x, y int; z complex128}{}`, `struct{x int; y int; z complex128}`},
+       } {
+               f, err := parseSrc(test.lit, "package p; var _ = "+test.lit)
+               if err != nil {
+                       t.Fatalf("%s: %v", test.lit, err)
+               }
+
+               info := &Info{
+                       Types: make(map[syntax.Expr]TypeAndValue),
+               }
+               if _, err = new(Config).Check("p", []*syntax.File{f}, info); err != nil {
+                       t.Fatalf("%s: %v", test.lit, err)
+               }
+
+               cmptype := func(x syntax.Expr, want string) {
+                       tv, ok := info.Types[x]
+                       if !ok {
+                               t.Errorf("%s: no Types entry found", test.lit)
+                               return
+                       }
+                       if tv.Type == nil {
+                               t.Errorf("%s: type is nil", test.lit)
+                               return
+                       }
+                       if got := tv.Type.String(); got != want {
+                               t.Errorf("%s: got %v, want %s", test.lit, got, want)
+                       }
+               }
+
+               // test type of composite literal expression
+               rhs := f.DeclList[0].(*syntax.VarDecl).Values
+               cmptype(rhs, test.typ)
+
+               // test type of composite literal type expression
+               cmptype(rhs.(*syntax.CompositeLit).Type, test.typ)
+       }
+}
+
+// TestObjectParents verifies that objects have parent scopes or not
+// as specified by the Object interface.
+func TestObjectParents(t *testing.T) {
+       const src = `
+package p
+
+const C = 0
+
+type T1 struct {
+       a, b int
+       T2
+}
+
+type T2 interface {
+       im1()
+       im2()
+}
+
+func (T1) m1() {}
+func (*T1) m2() {}
+
+func f(x int) { y := x; print(y) }
+`
+
+       f, err := parseSrc("src", src)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       info := &Info{
+               Defs: make(map[*syntax.Name]Object),
+       }
+       if _, err = new(Config).Check("p", []*syntax.File{f}, info); err != nil {
+               t.Fatal(err)
+       }
+
+       for ident, obj := range info.Defs {
+               if obj == nil {
+                       // only package names and implicit vars have a nil object
+                       // (in this test we only need to handle the package name)
+                       if ident.Value != "p" {
+                               t.Errorf("%v has nil object", ident)
+                       }
+                       continue
+               }
+
+               // struct fields, type-associated and interface methods
+               // have no parent scope
+               wantParent := true
+               switch obj := obj.(type) {
+               case *Var:
+                       if obj.IsField() {
+                               wantParent = false
+                       }
+               case *Func:
+                       if obj.Type().(*Signature).Recv() != nil { // method
+                               wantParent = false
+                       }
+               }
+
+               gotParent := obj.Parent() != nil
+               switch {
+               case gotParent && !wantParent:
+                       t.Errorf("%v: want no parent, got %s", ident, obj.Parent())
+               case !gotParent && wantParent:
+                       t.Errorf("%v: no parent found", ident)
+               }
+       }
+}
+
+// TestFailedImport tests that we don't get follow-on errors
+// elsewhere in a package due to failing to import a package.
+func TestFailedImport(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       const src = `
+package p
+
+import foo "go/types/thisdirectorymustnotexistotherwisethistestmayfail/foo" // should only see an error here
+
+const c = foo.C
+type T = foo.T
+var v T = c
+func f(x T) T { return foo.F(x) }
+`
+       f, err := parseSrc("src", src)
+       if err != nil {
+               t.Fatal(err)
+       }
+       files := []*syntax.File{f}
+
+       // type-check using all possible importers
+       for _, compiler := range []string{"gc", "gccgo", "source"} {
+               errcount := 0
+               conf := Config{
+                       Error: func(err error) {
+                               // we should only see the import error
+                               if errcount > 0 || !strings.Contains(err.Error(), "could not import") {
+                                       t.Errorf("for %s importer, got unexpected error: %v", compiler, err)
+                               }
+                               errcount++
+                       },
+                       //Importer: importer.For(compiler, nil),
+               }
+
+               info := &Info{
+                       Uses: make(map[*syntax.Name]Object),
+               }
+               pkg, _ := conf.Check("p", files, info)
+               if pkg == nil {
+                       t.Errorf("for %s importer, type-checking failed to return a package", compiler)
+                       continue
+               }
+
+               imports := pkg.Imports()
+               if len(imports) != 1 {
+                       t.Errorf("for %s importer, got %d imports, want 1", compiler, len(imports))
+                       continue
+               }
+               imp := imports[0]
+               if imp.Name() != "foo" {
+                       t.Errorf(`for %s importer, got %q, want "foo"`, compiler, imp.Name())
+                       continue
+               }
+
+               // verify that all uses of foo refer to the imported package foo (imp)
+               for ident, obj := range info.Uses {
+                       if ident.Value == "foo" {
+                               if obj, ok := obj.(*PkgName); ok {
+                                       if obj.Imported() != imp {
+                                               t.Errorf("%s resolved to %v; want %v", ident.Value, obj.Imported(), imp)
+                                       }
+                               } else {
+                                       t.Errorf("%s resolved to %v; want package name", ident.Value, obj)
+                               }
+                       }
+               }
+       }
+}
diff --git a/src/cmd/compile/internal/types2/assignments.go b/src/cmd/compile/internal/types2/assignments.go
new file mode 100644 (file)
index 0000000..b367aa7
--- /dev/null
@@ -0,0 +1,364 @@
+// UNREVIEWED
+// Copyright 2013 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.
+
+// This file implements initialization and assignment checks.
+
+package types2
+
+import "cmd/compile/internal/syntax"
+
+// assignment reports whether x can be assigned to a variable of type T,
+// if necessary by attempting to convert untyped values to the appropriate
+// type. context describes the context in which the assignment takes place.
+// Use T == nil to indicate assignment to an untyped blank identifier.
+// x.mode is set to invalid if the assignment failed.
+func (check *Checker) assignment(x *operand, T Type, context string) {
+       check.singleValue(x)
+
+       switch x.mode {
+       case invalid:
+               return // error reported before
+       case constant_, variable, mapindex, value, commaok, commaerr:
+               // ok
+       default:
+               // we may get here because of other problems (issue #39634, crash 12)
+               check.errorf(x, "cannot assign %s to %s in %s", x, T, context)
+               return
+       }
+
+       if isUntyped(x.typ) {
+               target := T
+               // spec: "If an untyped constant is assigned to a variable of interface
+               // type or the blank identifier, the constant is first converted to type
+               // bool, rune, int, float64, complex128 or string respectively, depending
+               // on whether the value is a boolean, rune, integer, floating-point, complex,
+               // or string constant."
+               if T == nil || IsInterface(T) {
+                       if T == nil && x.typ == Typ[UntypedNil] {
+                               check.errorf(x, "use of untyped nil in %s", context)
+                               x.mode = invalid
+                               return
+                       }
+                       target = Default(x.typ)
+               }
+               check.convertUntyped(x, target)
+               if x.mode == invalid {
+                       return
+               }
+       }
+       // x.typ is typed
+
+       // A generic (non-instantiated) function value cannot be assigned to a variable.
+       if sig := x.typ.Signature(); sig != nil && len(sig.tparams) > 0 {
+               check.errorf(x, "cannot use generic function %s without instantiation in %s", x, context)
+       }
+
+       // spec: "If a left-hand side is the blank identifier, any typed or
+       // non-constant value except for the predeclared identifier nil may
+       // be assigned to it."
+       if T == nil {
+               return
+       }
+
+       if reason := ""; !x.assignableTo(check, T, &reason) {
+               if check.conf.CompilerErrorMessages {
+                       check.errorf(x, "incompatible type: cannot use %s as %s value", x, T)
+               } else {
+                       if reason != "" {
+                               check.errorf(x, "cannot use %s as %s value in %s: %s", x, T, context, reason)
+                       } else {
+                               check.errorf(x, "cannot use %s as %s value in %s", x, T, context)
+                       }
+               }
+               x.mode = invalid
+       }
+}
+
+func (check *Checker) initConst(lhs *Const, x *operand) {
+       if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+               if lhs.typ == nil {
+                       lhs.typ = Typ[Invalid]
+               }
+               return
+       }
+
+       // rhs must be a constant
+       if x.mode != constant_ {
+               check.errorf(x, "%s is not constant", x)
+               if lhs.typ == nil {
+                       lhs.typ = Typ[Invalid]
+               }
+               return
+       }
+       assert(isConstType(x.typ))
+
+       // If the lhs doesn't have a type yet, use the type of x.
+       if lhs.typ == nil {
+               lhs.typ = x.typ
+       }
+
+       check.assignment(x, lhs.typ, "constant declaration")
+       if x.mode == invalid {
+               return
+       }
+
+       lhs.val = x.val
+}
+
+func (check *Checker) initVar(lhs *Var, x *operand, context string) Type {
+       if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+               if lhs.typ == nil {
+                       lhs.typ = Typ[Invalid]
+               }
+               lhs.used = true // avoid follow-on "declared but not used" errors
+               return nil
+       }
+
+       // If the lhs doesn't have a type yet, use the type of x.
+       if lhs.typ == nil {
+               typ := x.typ
+               if isUntyped(typ) {
+                       // convert untyped types to default types
+                       if typ == Typ[UntypedNil] {
+                               check.errorf(x, "use of untyped nil in %s", context)
+                               lhs.typ = Typ[Invalid]
+                               return nil
+                       }
+                       typ = Default(typ)
+               }
+               lhs.typ = typ
+       }
+
+       check.assignment(x, lhs.typ, context)
+       if x.mode == invalid {
+               return nil
+       }
+
+       return x.typ
+}
+
+func (check *Checker) assignVar(lhs syntax.Expr, x *operand) Type {
+       if x.mode == invalid || x.typ == Typ[Invalid] {
+               check.useLHS(lhs)
+               return nil
+       }
+
+       // Determine if the lhs is a (possibly parenthesized) identifier.
+       ident, _ := unparen(lhs).(*syntax.Name)
+
+       // Don't evaluate lhs if it is the blank identifier.
+       if ident != nil && ident.Value == "_" {
+               check.recordDef(ident, nil)
+               check.assignment(x, nil, "assignment to _ identifier")
+               if x.mode == invalid {
+                       return nil
+               }
+               return x.typ
+       }
+
+       // If the lhs is an identifier denoting a variable v, this assignment
+       // is not a 'use' of v. Remember current value of v.used and restore
+       // after evaluating the lhs via check.expr.
+       var v *Var
+       var v_used bool
+       if ident != nil {
+               if obj := check.lookup(ident.Value); obj != nil {
+                       // It's ok to mark non-local variables, but ignore variables
+                       // from other packages to avoid potential race conditions with
+                       // dot-imported variables.
+                       if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
+                               v = w
+                               v_used = v.used
+                       }
+               }
+       }
+
+       var z operand
+       check.expr(&z, lhs)
+       if v != nil {
+               v.used = v_used // restore v.used
+       }
+
+       if z.mode == invalid || z.typ == Typ[Invalid] {
+               return nil
+       }
+
+       // spec: "Each left-hand side operand must be addressable, a map index
+       // expression, or the blank identifier. Operands may be parenthesized."
+       switch z.mode {
+       case invalid:
+               return nil
+       case variable, mapindex:
+               // ok
+       default:
+               if sel, ok := z.expr.(*syntax.SelectorExpr); ok {
+                       var op operand
+                       check.expr(&op, sel.X)
+                       if op.mode == mapindex {
+                               check.errorf(&z, "cannot assign to struct field %s in map", ExprString(z.expr))
+                               return nil
+                       }
+               }
+               check.errorf(&z, "cannot assign to %s", &z)
+               return nil
+       }
+
+       check.assignment(x, z.typ, "assignment")
+       if x.mode == invalid {
+               return nil
+       }
+
+       return x.typ
+}
+
+// If returnPos is valid, initVars is called to type-check the assignment of
+// return expressions, and returnPos is the position of the return statement.
+func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnPos syntax.Pos) {
+       rhs, commaOk := check.exprList(orig_rhs, len(lhs) == 2 && !returnPos.IsKnown())
+
+       if len(lhs) != len(rhs) {
+               // invalidate lhs
+               for _, obj := range lhs {
+                       if obj.typ == nil {
+                               obj.typ = Typ[Invalid]
+                       }
+               }
+               // don't report an error if we already reported one
+               for _, x := range rhs {
+                       if x.mode == invalid {
+                               return
+                       }
+               }
+               if returnPos.IsKnown() {
+                       check.errorf(returnPos, "wrong number of return values (want %d, got %d)", len(lhs), len(rhs))
+                       return
+               }
+               check.errorf(rhs[0], "cannot initialize %d variables with %d values", len(lhs), len(rhs))
+               return
+       }
+
+       context := "assignment"
+       if returnPos.IsKnown() {
+               context = "return statement"
+       }
+
+       if commaOk {
+               var a [2]Type
+               for i := range a {
+                       a[i] = check.initVar(lhs[i], rhs[i], context)
+               }
+               check.recordCommaOkTypes(orig_rhs[0], a)
+               return
+       }
+
+       for i, lhs := range lhs {
+               check.initVar(lhs, rhs[i], context)
+       }
+}
+
+func (check *Checker) assignVars(lhs, orig_rhs []syntax.Expr) {
+       rhs, commaOk := check.exprList(orig_rhs, len(lhs) == 2)
+
+       if len(lhs) != len(rhs) {
+               check.useLHS(lhs...)
+               // don't report an error if we already reported one
+               for _, x := range rhs {
+                       if x.mode == invalid {
+                               return
+                       }
+               }
+               check.errorf(rhs[0], "cannot assign %d values to %d variables", len(rhs), len(lhs))
+               return
+       }
+
+       if commaOk {
+               var a [2]Type
+               for i := range a {
+                       a[i] = check.assignVar(lhs[i], rhs[i])
+               }
+               check.recordCommaOkTypes(orig_rhs[0], a)
+               return
+       }
+
+       for i, lhs := range lhs {
+               check.assignVar(lhs, rhs[i])
+       }
+}
+
+// unpack unpacks a *syntax.ListExpr into a list of syntax.Expr.
+// Helper introduced for the go/types -> types2 port.
+// TODO(gri) Should find a more efficient solution that doesn't
+//           require introduction of a new slice for simple
+//           expressions.
+func unpackExpr(x syntax.Expr) []syntax.Expr {
+       if x, _ := x.(*syntax.ListExpr); x != nil {
+               return x.ElemList
+       }
+       if x != nil {
+               return []syntax.Expr{x}
+       }
+       return nil
+}
+
+func (check *Checker) shortVarDecl(pos syntax.Pos, lhs, rhs []syntax.Expr) {
+       top := len(check.delayed)
+       scope := check.scope
+
+       // collect lhs variables
+       var newVars []*Var
+       var lhsVars = make([]*Var, len(lhs))
+       for i, lhs := range lhs {
+               var obj *Var
+               if ident, _ := lhs.(*syntax.Name); ident != nil {
+                       // Use the correct obj if the ident is redeclared. The
+                       // variable's scope starts after the declaration; so we
+                       // must use Scope.Lookup here and call Scope.Insert
+                       // (via check.declare) later.
+                       name := ident.Value
+                       if alt := scope.Lookup(name); alt != nil {
+                               // redeclared object must be a variable
+                               if alt, _ := alt.(*Var); alt != nil {
+                                       obj = alt
+                               } else {
+                                       check.errorf(lhs, "cannot assign to %s", lhs)
+                               }
+                               check.recordUse(ident, alt)
+                       } else {
+                               // declare new variable, possibly a blank (_) variable
+                               obj = NewVar(ident.Pos(), check.pkg, name, nil)
+                               if name != "_" {
+                                       newVars = append(newVars, obj)
+                               }
+                               check.recordDef(ident, obj)
+                       }
+               } else {
+                       check.useLHS(lhs)
+                       check.errorf(lhs, "cannot declare %s", lhs)
+               }
+               if obj == nil {
+                       obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
+               }
+               lhsVars[i] = obj
+       }
+
+       check.initVars(lhsVars, rhs, nopos)
+
+       // process function literals in rhs expressions before scope changes
+       check.processDelayed(top)
+
+       // declare new variables
+       if len(newVars) > 0 {
+               // spec: "The scope of a constant or variable identifier declared inside
+               // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
+               // for short variable declarations) and ends at the end of the innermost
+               // containing block."
+               scopePos := endPos(rhs[len(rhs)-1])
+               for _, obj := range newVars {
+                       check.declare(scope, nil, obj, scopePos) // recordObject already called
+               }
+       } else {
+               check.softErrorf(pos, "no new variables on left side of :=")
+       }
+}
diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go
new file mode 100644 (file)
index 0000000..43da6a1
--- /dev/null
@@ -0,0 +1,777 @@
+// UNREVIEWED
+// Copyright 2012 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.
+
+// This file implements typechecking of builtin function calls.
+
+package types2
+
+import (
+       "cmd/compile/internal/syntax"
+       "go/constant"
+       "go/token"
+)
+
+// builtin type-checks a call to the built-in specified by id and
+// reports whether the call is valid, with *x holding the result;
+// but x.expr is not set. If the call is invalid, the result is
+// false, and *x is undefined.
+//
+func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (_ bool) {
+       // append is the only built-in that permits the use of ... for the last argument
+       bin := predeclaredFuncs[id]
+       if call.HasDots && id != _Append {
+               //check.invalidOpf(call.Ellipsis, "invalid use of ... with built-in %s", bin.name)
+               check.invalidOpf(call, "invalid use of ... with built-in %s", bin.name)
+               check.use(call.ArgList...)
+               return
+       }
+
+       // For len(x) and cap(x) we need to know if x contains any function calls or
+       // receive operations. Save/restore current setting and set hasCallOrRecv to
+       // false for the evaluation of x so that we can check it afterwards.
+       // Note: We must do this _before_ calling exprList because exprList evaluates
+       //       all arguments.
+       if id == _Len || id == _Cap {
+               defer func(b bool) {
+                       check.hasCallOrRecv = b
+               }(check.hasCallOrRecv)
+               check.hasCallOrRecv = false
+       }
+
+       // determine actual arguments
+       var arg func(*operand, int) // TODO(gri) remove use of arg getter in favor of using xlist directly
+       nargs := len(call.ArgList)
+       switch id {
+       default:
+               // make argument getter
+               xlist, _ := check.exprList(call.ArgList, false)
+               arg = func(x *operand, i int) { *x = *xlist[i]; x.typ = expand(x.typ) }
+               nargs = len(xlist)
+               // evaluate first argument, if present
+               if nargs > 0 {
+                       arg(x, 0)
+                       if x.mode == invalid {
+                               return
+                       }
+               }
+       case _Make, _New, _Offsetof, _Trace:
+               // arguments require special handling
+       }
+
+       // check argument count
+       {
+               msg := ""
+               if nargs < bin.nargs {
+                       msg = "not enough"
+               } else if !bin.variadic && nargs > bin.nargs {
+                       msg = "too many"
+               }
+               if msg != "" {
+                       check.invalidOpf(call, "%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs)
+                       return
+               }
+       }
+
+       switch id {
+       case _Append:
+               // append(s S, x ...T) S, where T is the element type of S
+               // spec: "The variadic function append appends zero or more values x to s of type
+               // S, which must be a slice type, and returns the resulting slice, also of type S.
+               // The values x are passed to a parameter of type ...T where T is the element type
+               // of S and the respective parameter passing rules apply."
+               S := x.typ
+               var T Type
+               if s := S.Slice(); s != nil {
+                       T = s.elem
+               } else {
+                       check.invalidArgf(x, "%s is not a slice", x)
+                       return
+               }
+
+               // remember arguments that have been evaluated already
+               alist := []operand{*x}
+
+               // spec: "As a special case, append also accepts a first argument assignable
+               // to type []byte with a second argument of string type followed by ... .
+               // This form appends the bytes of the string.
+               if nargs == 2 && call.HasDots && x.assignableTo(check, NewSlice(universeByte), nil) {
+                       arg(x, 1)
+                       if x.mode == invalid {
+                               return
+                       }
+                       if isString(x.typ) {
+                               if check.Types != nil {
+                                       sig := makeSig(S, S, x.typ)
+                                       sig.variadic = true
+                                       check.recordBuiltinType(call.Fun, sig)
+                               }
+                               x.mode = value
+                               x.typ = S
+                               break
+                       }
+                       alist = append(alist, *x)
+                       // fallthrough
+               }
+
+               // check general case by creating custom signature
+               sig := makeSig(S, S, NewSlice(T)) // []T required for variadic signature
+               sig.variadic = true
+               var xlist []*operand
+               // convert []operand to []*operand
+               for i := range alist {
+                       xlist = append(xlist, &alist[i])
+               }
+               for i := len(alist); i < nargs; i++ {
+                       var x operand
+                       arg(&x, i)
+                       xlist = append(xlist, &x)
+               }
+               check.arguments(call, sig, xlist) // discard result (we know the result type)
+               // ok to continue even if check.arguments reported errors
+
+               x.mode = value
+               x.typ = S
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, sig)
+               }
+
+       case _Cap, _Len:
+               // cap(x)
+               // len(x)
+               mode := invalid
+               var typ Type
+               var val constant.Value
+               switch typ = implicitArrayDeref(optype(x.typ.Under())); t := typ.(type) {
+               case *Basic:
+                       if isString(t) && id == _Len {
+                               if x.mode == constant_ {
+                                       mode = constant_
+                                       val = constant.MakeInt64(int64(len(constant.StringVal(x.val))))
+                               } else {
+                                       mode = value
+                               }
+                       }
+
+               case *Array:
+                       mode = value
+                       // spec: "The expressions len(s) and cap(s) are constants
+                       // if the type of s is an array or pointer to an array and
+                       // the expression s does not contain channel receives or
+                       // function calls; in this case s is not evaluated."
+                       if !check.hasCallOrRecv {
+                               mode = constant_
+                               if t.len >= 0 {
+                                       val = constant.MakeInt64(t.len)
+                               } else {
+                                       val = constant.MakeUnknown()
+                               }
+                       }
+
+               case *Slice, *Chan:
+                       mode = value
+
+               case *Map:
+                       if id == _Len {
+                               mode = value
+                       }
+
+               case *Sum:
+                       if t.is(func(t Type) bool {
+                               switch t := t.Under().(type) {
+                               case *Basic:
+                                       if isString(t) && id == _Len {
+                                               return true
+                                       }
+                               case *Array, *Slice, *Chan:
+                                       return true
+                               case *Map:
+                                       if id == _Len {
+                                               return true
+                                       }
+                               }
+                               return false
+                       }) {
+                               mode = value
+                       }
+               }
+
+               if mode == invalid && typ != Typ[Invalid] {
+                       check.invalidArgf(x, "%s for %s", x, bin.name)
+                       return
+               }
+
+               x.mode = mode
+               x.typ = Typ[Int]
+               x.val = val
+               if check.Types != nil && mode != constant_ {
+                       check.recordBuiltinType(call.Fun, makeSig(x.typ, typ))
+               }
+
+       case _Close:
+               // close(c)
+               c := x.typ.Chan()
+               if c == nil {
+                       check.invalidArgf(x, "%s is not a channel", x)
+                       return
+               }
+               if c.dir == RecvOnly {
+                       check.invalidArgf(x, "%s must not be a receive-only channel", x)
+                       return
+               }
+
+               x.mode = novalue
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(nil, c))
+               }
+
+       case _Complex:
+               // complex(x, y floatT) complexT
+               var y operand
+               arg(&y, 1)
+               if y.mode == invalid {
+                       return
+               }
+
+               // convert or check untyped arguments
+               d := 0
+               if isUntyped(x.typ) {
+                       d |= 1
+               }
+               if isUntyped(y.typ) {
+                       d |= 2
+               }
+               switch d {
+               case 0:
+                       // x and y are typed => nothing to do
+               case 1:
+                       // only x is untyped => convert to type of y
+                       check.convertUntyped(x, y.typ)
+               case 2:
+                       // only y is untyped => convert to type of x
+                       check.convertUntyped(&y, x.typ)
+               case 3:
+                       // x and y are untyped =>
+                       // 1) if both are constants, convert them to untyped
+                       //    floating-point numbers if possible,
+                       // 2) if one of them is not constant (possible because
+                       //    it contains a shift that is yet untyped), convert
+                       //    both of them to float64 since they must have the
+                       //    same type to succeed (this will result in an error
+                       //    because shifts of floats are not permitted)
+                       if x.mode == constant_ && y.mode == constant_ {
+                               toFloat := func(x *operand) {
+                                       if isNumeric(x.typ) && constant.Sign(constant.Imag(x.val)) == 0 {
+                                               x.typ = Typ[UntypedFloat]
+                                       }
+                               }
+                               toFloat(x)
+                               toFloat(&y)
+                       } else {
+                               check.convertUntyped(x, Typ[Float64])
+                               check.convertUntyped(&y, Typ[Float64])
+                               // x and y should be invalid now, but be conservative
+                               // and check below
+                       }
+               }
+               if x.mode == invalid || y.mode == invalid {
+                       return
+               }
+
+               // both argument types must be identical
+               if !check.identical(x.typ, y.typ) {
+                       check.invalidOpf(x, "%s (mismatched types %s and %s)", call, x.typ, y.typ)
+                       return
+               }
+
+               // the argument types must be of floating-point type
+               f := func(x Type) Type {
+                       if t := x.Basic(); t != nil {
+                               switch t.kind {
+                               case Float32:
+                                       return Typ[Complex64]
+                               case Float64:
+                                       return Typ[Complex128]
+                               case UntypedFloat:
+                                       return Typ[UntypedComplex]
+                               }
+                       }
+                       return nil
+               }
+               resTyp := check.applyTypeFunc(f, x.typ)
+               if resTyp == nil {
+                       check.invalidArgf(x, "arguments have type %s, expected floating-point", x.typ)
+                       return
+               }
+
+               // if both arguments are constants, the result is a constant
+               if x.mode == constant_ && y.mode == constant_ {
+                       x.val = constant.BinaryOp(constant.ToFloat(x.val), token.ADD, constant.MakeImag(constant.ToFloat(y.val)))
+               } else {
+                       x.mode = value
+               }
+
+               if check.Types != nil && x.mode != constant_ {
+                       check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ, x.typ))
+               }
+
+               x.typ = resTyp
+
+       case _Copy:
+               // copy(x, y []T) int
+               var dst Type
+               if t := x.typ.Slice(); t != nil {
+                       dst = t.elem
+               }
+
+               var y operand
+               arg(&y, 1)
+               if y.mode == invalid {
+                       return
+               }
+               var src Type
+               switch t := optype(y.typ.Under()).(type) {
+               case *Basic:
+                       if isString(y.typ) {
+                               src = universeByte
+                       }
+               case *Slice:
+                       src = t.elem
+               }
+
+               if dst == nil || src == nil {
+                       check.invalidArgf(x, "copy expects slice arguments; found %s and %s", x, &y)
+                       return
+               }
+
+               if !check.identical(dst, src) {
+                       check.invalidArgf(x, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
+                       return
+               }
+
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ, y.typ))
+               }
+               x.mode = value
+               x.typ = Typ[Int]
+
+       case _Delete:
+               // delete(m, k)
+               m := x.typ.Map()
+               if m == nil {
+                       check.invalidArgf(x, "%s is not a map", x)
+                       return
+               }
+               arg(x, 1) // k
+               if x.mode == invalid {
+                       return
+               }
+
+               if !x.assignableTo(check, m.key, nil) {
+                       check.invalidArgf(x, "%s is not assignable to %s", x, m.key)
+                       return
+               }
+
+               x.mode = novalue
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(nil, m, m.key))
+               }
+
+       case _Imag, _Real:
+               // imag(complexT) floatT
+               // real(complexT) floatT
+
+               // convert or check untyped argument
+               if isUntyped(x.typ) {
+                       if x.mode == constant_ {
+                               // an untyped constant number can always be considered
+                               // as a complex constant
+                               if isNumeric(x.typ) {
+                                       x.typ = Typ[UntypedComplex]
+                               }
+                       } else {
+                               // an untyped non-constant argument may appear if
+                               // it contains a (yet untyped non-constant) shift
+                               // expression: convert it to complex128 which will
+                               // result in an error (shift of complex value)
+                               check.convertUntyped(x, Typ[Complex128])
+                               // x should be invalid now, but be conservative and check
+                               if x.mode == invalid {
+                                       return
+                               }
+                       }
+               }
+
+               // the argument must be of complex type
+               f := func(x Type) Type {
+                       if t := x.Basic(); t != nil {
+                               switch t.kind {
+                               case Complex64:
+                                       return Typ[Float32]
+                               case Complex128:
+                                       return Typ[Float64]
+                               case UntypedComplex:
+                                       return Typ[UntypedFloat]
+                               }
+                       }
+                       return nil
+               }
+               resTyp := check.applyTypeFunc(f, x.typ)
+               if resTyp == nil {
+                       check.invalidArgf(x, "argument has type %s, expected complex type", x.typ)
+                       return
+               }
+
+               // if the argument is a constant, the result is a constant
+               if x.mode == constant_ {
+                       if id == _Real {
+                               x.val = constant.Real(x.val)
+                       } else {
+                               x.val = constant.Imag(x.val)
+                       }
+               } else {
+                       x.mode = value
+               }
+
+               if check.Types != nil && x.mode != constant_ {
+                       check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ))
+               }
+
+               x.typ = resTyp
+
+       case _Make:
+               // make(T, n)
+               // make(T, n, m)
+               // (no argument evaluated yet)
+               arg0 := call.ArgList[0]
+               T := check.varType(arg0)
+               if T == Typ[Invalid] {
+                       return
+               }
+
+               min, max := -1, 10
+               var valid func(t Type) bool
+               valid = func(t Type) bool {
+                       var m int
+                       switch t := optype(t.Under()).(type) {
+                       case *Slice:
+                               m = 2
+                       case *Map, *Chan:
+                               m = 1
+                       case *Sum:
+                               return t.is(valid)
+                       default:
+                               return false
+                       }
+                       if m > min {
+                               min = m
+                       }
+                       if m+1 < max {
+                               max = m + 1
+                       }
+                       return true
+               }
+
+               if !valid(T) {
+                       check.invalidArgf(arg0, "cannot make %s; type must be slice, map, or channel", arg0)
+                       return
+               }
+               if nargs < min || max < nargs {
+                       if min == max {
+                               check.errorf(call, "%v expects %d arguments; found %d", call, min, nargs)
+                       } else {
+                               check.errorf(call, "%v expects %d or %d arguments; found %d", call, min, max, nargs)
+                       }
+                       return
+               }
+
+               types := []Type{T}
+               var sizes []int64 // constant integer arguments, if any
+               for _, arg := range call.ArgList[1:] {
+                       typ, size := check.index(arg, -1) // ok to continue with typ == Typ[Invalid]
+                       types = append(types, typ)
+                       if size >= 0 {
+                               sizes = append(sizes, size)
+                       }
+               }
+               if len(sizes) == 2 && sizes[0] > sizes[1] {
+                       check.invalidArgf(call.ArgList[1], "length and capacity swapped")
+                       // safe to continue
+               }
+               x.mode = value
+               x.typ = T
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(x.typ, types...))
+               }
+
+       case _New:
+               // new(T)
+               // (no argument evaluated yet)
+               T := check.varType(call.ArgList[0])
+               if T == Typ[Invalid] {
+                       return
+               }
+
+               x.mode = value
+               x.typ = &Pointer{base: T}
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(x.typ, T))
+               }
+
+       case _Panic:
+               // panic(x)
+               // record panic call if inside a function with result parameters
+               // (for use in Checker.isTerminating)
+               if check.sig != nil && check.sig.results.Len() > 0 {
+                       // function has result parameters
+                       p := check.isPanic
+                       if p == nil {
+                               // allocate lazily
+                               p = make(map[*syntax.CallExpr]bool)
+                               check.isPanic = p
+                       }
+                       p[call] = true
+               }
+
+               check.assignment(x, &emptyInterface, "argument to panic")
+               if x.mode == invalid {
+                       return
+               }
+
+               x.mode = novalue
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(nil, &emptyInterface))
+               }
+
+       case _Print, _Println:
+               // print(x, y, ...)
+               // println(x, y, ...)
+               var params []Type
+               if nargs > 0 {
+                       params = make([]Type, nargs)
+                       for i := 0; i < nargs; i++ {
+                               if i > 0 {
+                                       arg(x, i) // first argument already evaluated
+                               }
+                               check.assignment(x, nil, "argument to "+predeclaredFuncs[id].name)
+                               if x.mode == invalid {
+                                       // TODO(gri) "use" all arguments?
+                                       return
+                               }
+                               params[i] = x.typ
+                       }
+               }
+
+               x.mode = novalue
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(nil, params...))
+               }
+
+       case _Recover:
+               // recover() interface{}
+               x.mode = value
+               x.typ = &emptyInterface
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(x.typ))
+               }
+
+       case _Alignof:
+               // unsafe.Alignof(x T) uintptr
+               if x.typ.TypeParam() != nil {
+                       check.invalidOpf(call, "unsafe.Alignof undefined for %s", x)
+                       return
+               }
+               check.assignment(x, nil, "argument to unsafe.Alignof")
+               if x.mode == invalid {
+                       return
+               }
+
+               x.mode = constant_
+               x.val = constant.MakeInt64(check.conf.alignof(x.typ))
+               x.typ = Typ[Uintptr]
+               // result is constant - no need to record signature
+
+       case _Offsetof:
+               // unsafe.Offsetof(x T) uintptr, where x must be a selector
+               // (no argument evaluated yet)
+               arg0 := call.ArgList[0]
+               selx, _ := unparen(arg0).(*syntax.SelectorExpr)
+               if selx == nil {
+                       check.invalidArgf(arg0, "%s is not a selector expression", arg0)
+                       check.use(arg0)
+                       return
+               }
+
+               check.expr(x, selx.X)
+               if x.mode == invalid {
+                       return
+               }
+
+               base := derefStructPtr(x.typ)
+               sel := selx.Sel.Value
+               obj, index, indirect := check.lookupFieldOrMethod(base, false, check.pkg, sel)
+               switch obj.(type) {
+               case nil:
+                       check.invalidArgf(x, "%s has no single field %s", base, sel)
+                       return
+               case *Func:
+                       // TODO(gri) Using derefStructPtr may result in methods being found
+                       // that don't actually exist. An error either way, but the error
+                       // message is confusing. See: https://play.golang.org/p/al75v23kUy ,
+                       // but go/types reports: "invalid argument: x.m is a method value".
+                       check.invalidArgf(arg0, "%s is a method value", arg0)
+                       return
+               }
+               if indirect {
+                       check.invalidArgf(x, "field %s is embedded via a pointer in %s", sel, base)
+                       return
+               }
+
+               // TODO(gri) Should we pass x.typ instead of base (and indirect report if derefStructPtr indirected)?
+               check.recordSelection(selx, FieldVal, base, obj, index, false)
+
+               offs := check.conf.offsetof(base, index)
+               x.mode = constant_
+               x.val = constant.MakeInt64(offs)
+               x.typ = Typ[Uintptr]
+               // result is constant - no need to record signature
+
+       case _Sizeof:
+               // unsafe.Sizeof(x T) uintptr
+               if x.typ.TypeParam() != nil {
+                       check.invalidOpf(call, "unsafe.Sizeof undefined for %s", x)
+                       return
+               }
+               check.assignment(x, nil, "argument to unsafe.Sizeof")
+               if x.mode == invalid {
+                       return
+               }
+
+               x.mode = constant_
+               x.val = constant.MakeInt64(check.conf.sizeof(x.typ))
+               x.typ = Typ[Uintptr]
+               // result is constant - no need to record signature
+
+       case _Assert:
+               // assert(pred) causes a typechecker error if pred is false.
+               // The result of assert is the value of pred if there is no error.
+               // Note: assert is only available in self-test mode.
+               if x.mode != constant_ || !isBoolean(x.typ) {
+                       check.invalidArgf(x, "%s is not a boolean constant", x)
+                       return
+               }
+               if x.val.Kind() != constant.Bool {
+                       check.errorf(x, "internal error: value of %s should be a boolean constant", x)
+                       return
+               }
+               if !constant.BoolVal(x.val) {
+                       check.errorf(call, "%v failed", call)
+                       // compile-time assertion failure - safe to continue
+               }
+               // result is constant - no need to record signature
+
+       case _Trace:
+               // trace(x, y, z, ...) dumps the positions, expressions, and
+               // values of its arguments. The result of trace is the value
+               // of the first argument.
+               // Note: trace is only available in self-test mode.
+               // (no argument evaluated yet)
+               if nargs == 0 {
+                       check.dump("%v: trace() without arguments", posFor(call))
+                       x.mode = novalue
+                       break
+               }
+               var t operand
+               x1 := x
+               for _, arg := range call.ArgList {
+                       check.rawExpr(x1, arg, nil) // permit trace for types, e.g.: new(trace(T))
+                       check.dump("%v: %s", posFor(x1), x1)
+                       x1 = &t // use incoming x only for first argument
+               }
+               // trace is only available in test mode - no need to record signature
+
+       default:
+               unreachable()
+       }
+
+       return true
+}
+
+// applyTypeFunc applies f to x. If x is a type parameter,
+// the result is a type parameter constrained by an new
+// interface bound. The type bounds for that interface
+// are computed by applying f to each of the type bounds
+// of x. If any of these applications of f return nil,
+// applyTypeFunc returns nil.
+// If x is not a type parameter, the result is f(x).
+func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
+       if tp := x.TypeParam(); tp != nil {
+               // Test if t satisfies the requirements for the argument
+               // type and collect possible result types at the same time.
+               var rtypes []Type
+               if !tp.Bound().is(func(x Type) bool {
+                       if r := f(x); r != nil {
+                               rtypes = append(rtypes, r)
+                               return true
+                       }
+                       return false
+               }) {
+                       return nil
+               }
+
+               // TODO(gri) Would it be ok to return just the one type
+               //           if len(rtypes) == 1? What about top-level
+               //           uses of real() where the result is used to
+               //           define type and initialize a variable?
+
+               // construct a suitable new type parameter
+               tpar := NewTypeName(nopos, nil /* = Universe pkg */, "<type parameter>", nil)
+               ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect
+               tsum := NewSum(rtypes)
+               ptyp.bound = &Interface{types: tsum, allMethods: markComplete, allTypes: tsum}
+
+               return ptyp
+       }
+
+       return f(x)
+}
+
+// makeSig makes a signature for the given argument and result types.
+// Default types are used for untyped arguments, and res may be nil.
+func makeSig(res Type, args ...Type) *Signature {
+       list := make([]*Var, len(args))
+       for i, param := range args {
+               list[i] = NewVar(nopos, nil, "", Default(param))
+       }
+       params := NewTuple(list...)
+       var result *Tuple
+       if res != nil {
+               assert(!isUntyped(res))
+               result = NewTuple(NewVar(nopos, nil, "", res))
+       }
+       return &Signature{params: params, results: result}
+}
+
+// implicitArrayDeref returns A if typ is of the form *A and A is an array;
+// otherwise it returns typ.
+//
+func implicitArrayDeref(typ Type) Type {
+       if p, ok := typ.(*Pointer); ok {
+               if a := p.base.Array(); a != nil {
+                       return a
+               }
+       }
+       return typ
+}
+
+// unparen returns e with any enclosing parentheses stripped.
+func unparen(e syntax.Expr) syntax.Expr {
+       for {
+               p, ok := e.(*syntax.ParenExpr)
+               if !ok {
+                       return e
+               }
+               e = p.X
+       }
+}
diff --git a/src/cmd/compile/internal/types2/builtins_test.go b/src/cmd/compile/internal/types2/builtins_test.go
new file mode 100644 (file)
index 0000000..9f737bc
--- /dev/null
@@ -0,0 +1,219 @@
+// UNREVIEWED
+// Copyright 2013 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/syntax"
+       "fmt"
+       "testing"
+
+       . "cmd/compile/internal/types2"
+)
+
+var builtinCalls = []struct {
+       name, src, sig string
+}{
+       {"append", `var s []int; _ = append(s)`, `func([]int, ...int) []int`},
+       {"append", `var s []int; _ = append(s, 0)`, `func([]int, ...int) []int`},
+       {"append", `var s []int; _ = (append)(s, 0)`, `func([]int, ...int) []int`},
+       {"append", `var s []byte; _ = ((append))(s, 0)`, `func([]byte, ...byte) []byte`},
+       {"append", `var s []byte; _ = append(s, "foo"...)`, `func([]byte, string...) []byte`},
+       {"append", `type T []byte; var s T; var str string; _ = append(s, str...)`, `func(p.T, string...) p.T`},
+       {"append", `type T []byte; type U string; var s T; var str U; _ = append(s, str...)`, `func(p.T, p.U...) p.T`},
+
+       {"cap", `var s [10]int; _ = cap(s)`, `invalid type`},  // constant
+       {"cap", `var s [10]int; _ = cap(&s)`, `invalid type`}, // constant
+       {"cap", `var s []int64; _ = cap(s)`, `func([]int64) int`},
+       {"cap", `var c chan<-bool; _ = cap(c)`, `func(chan<- bool) int`},
+
+       {"len", `_ = len("foo")`, `invalid type`}, // constant
+       {"len", `var s string; _ = len(s)`, `func(string) int`},
+       {"len", `var s [10]int; _ = len(s)`, `invalid type`},  // constant
+       {"len", `var s [10]int; _ = len(&s)`, `invalid type`}, // constant
+       {"len", `var s []int64; _ = len(s)`, `func([]int64) int`},
+       {"len", `var c chan<-bool; _ = len(c)`, `func(chan<- bool) int`},
+       {"len", `var m map[string]float32; _ = len(m)`, `func(map[string]float32) int`},
+
+       {"close", `var c chan int; close(c)`, `func(chan int)`},
+       {"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
+
+       {"complex", `_ = complex(1, 0)`, `invalid type`}, // constant
+       {"complex", `var re float32; _ = complex(re, 1.0)`, `func(float32, float32) complex64`},
+       {"complex", `var im float64; _ = complex(1, im)`, `func(float64, float64) complex128`},
+       {"complex", `type F32 float32; var re, im F32; _ = complex(re, im)`, `func(p.F32, p.F32) complex64`},
+       {"complex", `type F64 float64; var re, im F64; _ = complex(re, im)`, `func(p.F64, p.F64) complex128`},
+
+       {"copy", `var src, dst []byte; copy(dst, src)`, `func([]byte, []byte) int`},
+       {"copy", `type T [][]int; var src, dst T; _ = copy(dst, src)`, `func(p.T, p.T) int`},
+       {"copy", `var src string; var dst []byte; copy(dst, src)`, `func([]byte, string) int`},
+       {"copy", `type T string; type U []byte; var src T; var dst U; copy(dst, src)`, `func(p.U, p.T) int`},
+       {"copy", `var dst []byte; copy(dst, "hello")`, `func([]byte, string) int`},
+
+       {"delete", `var m map[string]bool; delete(m, "foo")`, `func(map[string]bool, string)`},
+       {"delete", `type (K string; V int); var m map[K]V; delete(m, "foo")`, `func(map[p.K]p.V, p.K)`},
+
+       {"imag", `_ = imag(1i)`, `invalid type`}, // constant
+       {"imag", `var c complex64; _ = imag(c)`, `func(complex64) float32`},
+       {"imag", `var c complex128; _ = imag(c)`, `func(complex128) float64`},
+       {"imag", `type C64 complex64; var c C64; _ = imag(c)`, `func(p.C64) float32`},
+       {"imag", `type C128 complex128; var c C128; _ = imag(c)`, `func(p.C128) float64`},
+
+       {"real", `_ = real(1i)`, `invalid type`}, // constant
+       {"real", `var c complex64; _ = real(c)`, `func(complex64) float32`},
+       {"real", `var c complex128; _ = real(c)`, `func(complex128) float64`},
+       {"real", `type C64 complex64; var c C64; _ = real(c)`, `func(p.C64) float32`},
+       {"real", `type C128 complex128; var c C128; _ = real(c)`, `func(p.C128) float64`},
+
+       {"make", `_ = make([]int, 10)`, `func([]int, int) []int`},
+       {"make", `type T []byte; _ = make(T, 10, 20)`, `func(p.T, int, int) p.T`},
+
+       // issue #37349
+       {"make", `              _ = make([]int, 0   )`, `func([]int, int) []int`},
+       {"make", `var l    int; _ = make([]int, l   )`, `func([]int, int) []int`},
+       {"make", `              _ = make([]int, 0, 0)`, `func([]int, int, int) []int`},
+       {"make", `var l    int; _ = make([]int, l, 0)`, `func([]int, int, int) []int`},
+       {"make", `var    c int; _ = make([]int, 0, c)`, `func([]int, int, int) []int`},
+       {"make", `var l, c int; _ = make([]int, l, c)`, `func([]int, int, int) []int`},
+
+       // issue #37393
+       {"make", `                _ = make([]int       , 0   )`, `func([]int, int) []int`},
+       {"make", `var l    byte ; _ = make([]int8      , l   )`, `func([]int8, byte) []int8`},
+       {"make", `                _ = make([]int16     , 0, 0)`, `func([]int16, int, int) []int16`},
+       {"make", `var l    int16; _ = make([]string    , l, 0)`, `func([]string, int16, int) []string`},
+       {"make", `var    c int32; _ = make([]float64   , 0, c)`, `func([]float64, int, int32) []float64`},
+       {"make", `var l, c uint ; _ = make([]complex128, l, c)`, `func([]complex128, uint, uint) []complex128`},
+
+       {"new", `_ = new(int)`, `func(int) *int`},
+       {"new", `type T struct{}; _ = new(T)`, `func(p.T) *p.T`},
+
+       {"panic", `panic(0)`, `func(interface{})`},
+       {"panic", `panic("foo")`, `func(interface{})`},
+
+       {"print", `print()`, `func()`},
+       {"print", `print(0)`, `func(int)`},
+       {"print", `print(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
+
+       {"println", `println()`, `func()`},
+       {"println", `println(0)`, `func(int)`},
+       {"println", `println(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
+
+       {"recover", `recover()`, `func() interface{}`},
+       {"recover", `_ = recover()`, `func() interface{}`},
+
+       {"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`},                 // constant
+       {"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant
+
+       {"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`},           // constant
+       {"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant
+
+       {"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`},                 // constant
+       {"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant
+
+       {"assert", `assert(true)`, `invalid type`},                                    // constant
+       {"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant
+
+       // no tests for trace since it produces output as a side-effect
+}
+
+func TestBuiltinSignatures(t *testing.T) {
+       DefPredeclaredTestFuncs()
+
+       seen := map[string]bool{"trace": true} // no test for trace built-in; add it manually
+       for _, call := range builtinCalls {
+               testBuiltinSignature(t, call.name, call.src, call.sig)
+               seen[call.name] = true
+       }
+
+       // make sure we didn't miss one
+       for _, name := range Universe.Names() {
+               if _, ok := Universe.Lookup(name).(*Builtin); ok && !seen[name] {
+                       t.Errorf("missing test for %s", name)
+               }
+       }
+       for _, name := range Unsafe.Scope().Names() {
+               if _, ok := Unsafe.Scope().Lookup(name).(*Builtin); ok && !seen[name] {
+                       t.Errorf("missing test for unsafe.%s", name)
+               }
+       }
+}
+
+func testBuiltinSignature(t *testing.T, name, src0, want string) {
+       src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _() { %s }`, src0)
+       f, err := parseSrc("", src)
+       if err != nil {
+               t.Errorf("%s: %s", src0, err)
+               return
+       }
+
+       conf := Config{Importer: defaultImporter()}
+       uses := make(map[*syntax.Name]Object)
+       types := make(map[syntax.Expr]TypeAndValue)
+       _, err = conf.Check(f.PkgName.Value, []*syntax.File{f}, &Info{Uses: uses, Types: types})
+       if err != nil {
+               t.Errorf("%s: %s", src0, err)
+               return
+       }
+
+       // find called function
+       n := 0
+       var fun syntax.Expr
+       for x := range types {
+               if call, _ := x.(*syntax.CallExpr); call != nil {
+                       fun = call.Fun
+                       n++
+               }
+       }
+       if n != 1 {
+               t.Errorf("%s: got %d CallExprs; want 1", src0, n)
+               return
+       }
+
+       // check recorded types for fun and descendents (may be parenthesized)
+       for {
+               // the recorded type for the built-in must match the wanted signature
+               typ := types[fun].Type
+               if typ == nil {
+                       t.Errorf("%s: no type recorded for %s", src0, ExprString(fun))
+                       return
+               }
+               if got := typ.String(); got != want {
+                       t.Errorf("%s: got type %s; want %s", src0, got, want)
+                       return
+               }
+
+               // called function must be a (possibly parenthesized, qualified)
+               // identifier denoting the expected built-in
+               switch p := fun.(type) {
+               case *syntax.Name:
+                       obj := uses[p]
+                       if obj == nil {
+                               t.Errorf("%s: no object found for %s", src0, p.Value)
+                               return
+                       }
+                       bin, _ := obj.(*Builtin)
+                       if bin == nil {
+                               t.Errorf("%s: %s does not denote a built-in", src0, p.Value)
+                               return
+                       }
+                       if bin.Name() != name {
+                               t.Errorf("%s: got built-in %s; want %s", src0, bin.Name(), name)
+                               return
+                       }
+                       return // we're done
+
+               case *syntax.ParenExpr:
+                       fun = p.X // unpack
+
+               case *syntax.SelectorExpr:
+                       // built-in from package unsafe - ignore details
+                       return // we're done
+
+               default:
+                       t.Errorf("%s: invalid function call", src0)
+                       return
+               }
+       }
+}
diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go
new file mode 100644 (file)
index 0000000..5a7ae22
--- /dev/null
@@ -0,0 +1,816 @@
+// UNREVIEWED
+// Copyright 2013 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.
+
+// This file implements typechecking of call and selector expressions.
+
+package types2
+
+import (
+       "cmd/compile/internal/syntax"
+       "strings"
+       "unicode"
+)
+
+// funcInst type-checks a function instantiaton inst and returns the result in x.
+// The operand x must be the evaluation of inst.X and its type must be a signature.
+func (check *Checker) funcInst(x *operand, inst *syntax.IndexExpr) {
+       args, ok := check.exprOrTypeList(unpackExpr(inst.Index))
+       if ok && len(args) > 0 && args[0].mode != typexpr {
+               check.errorf(args[0], "%s is not a type", args[0])
+               ok = false
+       }
+       if !ok {
+               x.mode = invalid
+               x.expr = inst
+               return
+       }
+
+       // check number of type arguments
+       n := len(args)
+       sig := x.typ.(*Signature)
+       if !check.conf.InferFromConstraints && n != len(sig.tparams) || n > len(sig.tparams) {
+               check.errorf(args[n-1], "got %d type arguments but want %d", n, len(sig.tparams))
+               x.mode = invalid
+               x.expr = inst
+               return
+       }
+
+       // collect types
+       targs := make([]Type, n)
+       poslist := make([]syntax.Pos, n)
+       for i, a := range args {
+               if a.mode != typexpr {
+                       // error was reported earlier
+                       x.mode = invalid
+                       x.expr = inst
+                       return
+               }
+               targs[i] = a.typ
+               poslist[i] = a.Pos()
+       }
+
+       // if we don't have enough type arguments, use constraint type inference
+       var inferred bool
+       if n < len(sig.tparams) {
+               var failed int
+               targs, failed = check.inferB(sig.tparams, targs)
+               if targs == nil {
+                       // error was already reported
+                       x.mode = invalid
+                       x.expr = inst
+                       return
+               }
+               if failed >= 0 {
+                       // at least one type argument couldn't be inferred
+                       assert(targs[failed] == nil)
+                       tpar := sig.tparams[failed]
+                       check.errorf(inst, "cannot infer %s (%s) (%s)", tpar.name, tpar.pos, targs)
+                       x.mode = invalid
+                       x.expr = inst
+                       return
+               }
+               // all type arguments were inferred sucessfully
+               if debug {
+                       for _, targ := range targs {
+                               assert(targ != nil)
+                       }
+               }
+               //check.dump("### inferred targs = %s", targs)
+               n = len(targs)
+               inferred = true
+       }
+       assert(n == len(sig.tparams))
+
+       // instantiate function signature
+       for i, typ := range targs {
+               // some positions may be missing if types are inferred
+               var pos syntax.Pos
+               if i < len(poslist) {
+                       pos = poslist[i]
+               }
+               check.ordinaryType(pos, typ)
+       }
+       res := check.instantiate(x.Pos(), sig, targs, poslist).(*Signature)
+       assert(res.tparams == nil) // signature is not generic anymore
+       if inferred {
+               check.recordInferred(inst, targs, res)
+       }
+       x.typ = res
+       x.mode = value
+       x.expr = inst
+}
+
+func (check *Checker) call(x *operand, call *syntax.CallExpr) exprKind {
+       check.exprOrType(x, call.Fun)
+
+       switch x.mode {
+       case invalid:
+               check.use(call.ArgList...)
+               x.expr = call
+               return statement
+
+       case typexpr:
+               // conversion
+               T := x.typ
+               x.mode = invalid
+               switch n := len(call.ArgList); n {
+               case 0:
+                       check.errorf(call, "missing argument in conversion to %s", T)
+               case 1:
+                       check.expr(x, call.ArgList[0])
+                       if x.mode != invalid {
+                               if t := T.Interface(); t != nil {
+                                       check.completeInterface(nopos, t)
+                                       if t.IsConstraint() {
+                                               check.errorf(call, "cannot use interface %s in conversion (contains type list or is comparable)", T)
+                                               break
+                                       }
+                               }
+                               if call.HasDots {
+                                       check.errorf(call.ArgList[0], "invalid use of ... in type conversion to %s", T)
+                                       break
+                               }
+                               check.conversion(x, T)
+                       }
+               default:
+                       check.use(call.ArgList...)
+                       check.errorf(call.ArgList[n-1], "too many arguments in conversion to %s", T)
+               }
+               x.expr = call
+               return conversion
+
+       case builtin:
+               id := x.id
+               if !check.builtin(x, call, id) {
+                       x.mode = invalid
+               }
+               x.expr = call
+               // a non-constant result implies a function call
+               if x.mode != invalid && x.mode != constant_ {
+                       check.hasCallOrRecv = true
+               }
+               return predeclaredFuncs[id].kind
+
+       default:
+               // function/method call
+               cgocall := x.mode == cgofunc
+
+               sig := x.typ.Signature()
+               if sig == nil {
+                       check.invalidOpf(x, "cannot call non-function %s", x)
+                       x.mode = invalid
+                       x.expr = call
+                       return statement
+               }
+
+               // evaluate arguments
+               args, ok := check.exprOrTypeList(call.ArgList)
+               if !ok {
+                       x.mode = invalid
+                       x.expr = call
+                       return expression
+               }
+
+               sig = check.arguments(call, sig, args)
+
+               // determine result
+               switch sig.results.Len() {
+               case 0:
+                       x.mode = novalue
+               case 1:
+                       if cgocall {
+                               x.mode = commaerr
+                       } else {
+                               x.mode = value
+                       }
+                       x.typ = sig.results.vars[0].typ // unpack tuple
+               default:
+                       x.mode = value
+                       x.typ = sig.results
+               }
+               x.expr = call
+               check.hasCallOrRecv = true
+
+               // if type inference failed, a parametrized result must be invalidated
+               // (operands cannot have a parametrized type)
+               if x.mode == value && len(sig.tparams) > 0 && isParameterized(sig.tparams, x.typ) {
+                       x.mode = invalid
+               }
+
+               return statement
+       }
+}
+
+// exprOrTypeList returns a list of operands and reports an error if the
+// list contains a mix of values and types (ignoring invalid operands).
+// TODO(gri) Now we can split this into exprList and typeList.
+func (check *Checker) exprOrTypeList(elist []syntax.Expr) (xlist []*operand, ok bool) {
+       ok = true
+
+       switch len(elist) {
+       case 0:
+               // nothing to do
+
+       case 1:
+               // single (possibly comma-ok) value or type, or function returning multiple values
+               e := elist[0]
+               var x operand
+               check.multiExprOrType(&x, e)
+               if t, ok := x.typ.(*Tuple); ok && x.mode != invalid && x.mode != typexpr {
+                       // multiple values
+                       xlist = make([]*operand, t.Len())
+                       for i, v := range t.vars {
+                               xlist[i] = &operand{mode: value, expr: e, typ: v.typ}
+                       }
+                       break
+               }
+
+               check.instantiatedOperand(&x)
+
+               // exactly one (possibly invalid or comma-ok) value or type
+               xlist = []*operand{&x}
+
+       default:
+               // multiple (possibly invalid) values or types
+               xlist = make([]*operand, len(elist))
+               ntypes := 0
+               for i, e := range elist {
+                       var x operand
+                       check.exprOrType(&x, e)
+                       xlist[i] = &x
+                       switch x.mode {
+                       case invalid:
+                               ntypes = len(xlist) // make 'if' condition fail below (no additional error in this case)
+                       case typexpr:
+                               ntypes++
+                               check.instantiatedOperand(&x)
+                       }
+               }
+               if 0 < ntypes && ntypes < len(xlist) {
+                       check.errorf(xlist[0], "mix of value and type expressions")
+                       ok = false
+               }
+       }
+
+       return
+}
+
+func (check *Checker) exprList(elist []syntax.Expr, allowCommaOk bool) (xlist []*operand, commaOk bool) {
+       switch len(elist) {
+       case 0:
+               // nothing to do
+
+       case 1:
+               // single (possibly comma-ok) value, or function returning multiple values
+               e := elist[0]
+               var x operand
+               check.multiExpr(&x, e)
+               if t, ok := x.typ.(*Tuple); ok && x.mode != invalid {
+                       // multiple values
+                       xlist = make([]*operand, t.Len())
+                       for i, v := range t.vars {
+                               xlist[i] = &operand{mode: value, expr: e, typ: v.typ}
+                       }
+                       break
+               }
+
+               // exactly one (possibly invalid or comma-ok) value
+               xlist = []*operand{&x}
+               if allowCommaOk && (x.mode == mapindex || x.mode == commaok || x.mode == commaerr) {
+                       x.mode = value
+                       xlist = append(xlist, &operand{mode: value, expr: e, typ: Typ[UntypedBool]})
+                       commaOk = true
+               }
+
+       default:
+               // multiple (possibly invalid) values
+               xlist = make([]*operand, len(elist))
+               for i, e := range elist {
+                       var x operand
+                       check.expr(&x, e)
+                       xlist[i] = &x
+               }
+       }
+
+       return
+}
+
+func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, args []*operand) (rsig *Signature) {
+       rsig = sig
+
+       // TODO(gri) try to eliminate this extra verification loop
+       for _, a := range args {
+               switch a.mode {
+               case typexpr:
+                       check.errorf(a, "%s used as value", a)
+                       return
+               case invalid:
+                       return
+               }
+       }
+
+       // Function call argument/parameter count requirements
+       //
+       //               | standard call    | dotdotdot call |
+       // --------------+------------------+----------------+
+       // standard func | nargs == npars   | invalid        |
+       // --------------+------------------+----------------+
+       // variadic func | nargs >= npars-1 | nargs == npars |
+       // --------------+------------------+----------------+
+
+       nargs := len(args)
+       npars := sig.params.Len()
+       ddd := call.HasDots
+
+       // set up parameters
+       sig_params := sig.params // adjusted for variadic functions (may be nil for empty parameter lists!)
+       adjusted := false        // indicates if sig_params is different from t.params
+       if sig.variadic {
+               if ddd {
+                       // variadic_func(a, b, c...)
+                       if len(call.ArgList) == 1 && nargs > 1 {
+                               // f()... is not permitted if f() is multi-valued
+                               //check.errorf(call.Ellipsis, "cannot use ... with %d-valued %s", nargs, call.ArgList[0])
+                               check.errorf(call, "cannot use ... with %d-valued %s", nargs, call.ArgList[0])
+                               return
+                       }
+               } else {
+                       // variadic_func(a, b, c)
+                       if nargs >= npars-1 {
+                               // Create custom parameters for arguments: keep
+                               // the first npars-1 parameters and add one for
+                               // each argument mapping to the ... parameter.
+                               vars := make([]*Var, npars-1) // npars > 0 for variadic functions
+                               copy(vars, sig.params.vars)
+                               last := sig.params.vars[npars-1]
+                               typ := last.typ.(*Slice).elem
+                               for len(vars) < nargs {
+                                       vars = append(vars, NewParam(last.pos, last.pkg, last.name, typ))
+                               }
+                               sig_params = NewTuple(vars...) // possibly nil!
+                               adjusted = true
+                               npars = nargs
+                       } else {
+                               // nargs < npars-1
+                               npars-- // for correct error message below
+                       }
+               }
+       } else {
+               if ddd {
+                       // standard_func(a, b, c...)
+                       //check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun)
+                       check.errorf(call, "cannot use ... in call to non-variadic %s", call.Fun)
+                       return
+               }
+               // standard_func(a, b, c)
+       }
+
+       // check argument count
+       switch {
+       case nargs < npars:
+               check.errorf(call, "not enough arguments in call to %s", call.Fun)
+               return
+       case nargs > npars:
+               check.errorf(args[npars], "too many arguments in call to %s", call.Fun) // report at first extra argument
+               return
+       }
+
+       // infer type arguments and instantiate signature if necessary
+       if len(sig.tparams) > 0 {
+               // TODO(gri) provide position information for targs so we can feed
+               //           it to the instantiate call for better error reporting
+               targs, failed := check.infer(sig.tparams, sig_params, args)
+               if targs == nil {
+                       return // error already reported
+               }
+               if failed >= 0 {
+                       // Some type arguments couldn't be inferred. Use
+                       // bounds type inference to try to make progress.
+                       if check.conf.InferFromConstraints {
+                               targs, failed = check.inferB(sig.tparams, targs)
+                               if targs == nil {
+                                       return // error already reported
+                               }
+                       }
+                       if failed >= 0 {
+                               // at least one type argument couldn't be inferred
+                               assert(targs[failed] == nil)
+                               tpar := sig.tparams[failed]
+                               // TODO(gri) here we'd like to use the position of the call's ')'
+                               check.errorf(call.Pos(), "cannot infer %s (%s) (%s)", tpar.name, tpar.pos, targs)
+                               return
+                       }
+               }
+               // all type arguments were inferred sucessfully
+               if debug {
+                       for _, targ := range targs {
+                               assert(targ != nil)
+                       }
+               }
+               //check.dump("### inferred targs = %s", targs)
+
+               // compute result signature
+               rsig = check.instantiate(call.Pos(), sig, targs, nil).(*Signature)
+               assert(rsig.tparams == nil) // 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 {
+                       sig_params = check.subst(call.Pos(), sig_params, makeSubstMap(sig.tparams, targs)).(*Tuple)
+               } else {
+                       sig_params = rsig.params
+               }
+       }
+
+       // check arguments
+       for i, a := range args {
+               check.assignment(a, sig_params.vars[i].typ, "argument")
+       }
+
+       return
+}
+
+var cgoPrefixes = [...]string{
+       "_Ciconst_",
+       "_Cfconst_",
+       "_Csconst_",
+       "_Ctype_",
+       "_Cvar_", // actually a pointer to the var
+       "_Cfpvar_fp_",
+       "_Cfunc_",
+       "_Cmacro_", // function to evaluate the expanded expression
+}
+
+func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
+       // these must be declared before the "goto Error" statements
+       var (
+               obj      Object
+               index    []int
+               indirect bool
+       )
+
+       sel := e.Sel.Value
+       // If the identifier refers to a package, handle everything here
+       // so we don't need a "package" mode for operands: package names
+       // can only appear in qualified identifiers which are mapped to
+       // selector expressions.
+       if ident, ok := e.X.(*syntax.Name); ok {
+               obj := check.lookup(ident.Value)
+               if pname, _ := obj.(*PkgName); pname != nil {
+                       assert(pname.pkg == check.pkg)
+                       check.recordUse(ident, pname)
+                       pname.used = true
+                       pkg := pname.imported
+
+                       var exp Object
+                       funcMode := value
+                       if pkg.cgo {
+                               // cgo special cases C.malloc: it's
+                               // rewritten to _CMalloc and does not
+                               // support two-result calls.
+                               if sel == "malloc" {
+                                       sel = "_CMalloc"
+                               } else {
+                                       funcMode = cgofunc
+                               }
+                               for _, prefix := range cgoPrefixes {
+                                       // cgo objects are part of the current package (in file
+                                       // _cgo_gotypes.go). Use regular lookup.
+                                       _, exp = check.scope.LookupParent(prefix+sel, check.pos)
+                                       if exp != nil {
+                                               break
+                                       }
+                               }
+                               if exp == nil {
+                                       check.errorf(e.Sel, "%s not declared by package C", sel)
+                                       goto Error
+                               }
+                               check.objDecl(exp, nil)
+                       } else {
+                               exp = pkg.scope.Lookup(sel)
+                               if exp == nil {
+                                       if !pkg.fake {
+                                               if check.conf.CompilerErrorMessages {
+                                                       check.errorf(e.Sel, "undefined: %s.%s", pkg.name, sel)
+                                               } else {
+                                                       check.errorf(e.Sel, "%s not declared by package %s", sel, pkg.name)
+                                               }
+                                       }
+                                       goto Error
+                               }
+                               if !exp.Exported() {
+                                       check.errorf(e.Sel, "%s not exported by package %s", sel, pkg.name)
+                                       // ok to continue
+                               }
+                       }
+                       check.recordUse(e.Sel, exp)
+
+                       // Simplified version of the code for *syntax.Names:
+                       // - imported objects are always fully initialized
+                       switch exp := exp.(type) {
+                       case *Const:
+                               assert(exp.Val() != nil)
+                               x.mode = constant_
+                               x.typ = exp.typ
+                               x.val = exp.val
+                       case *TypeName:
+                               x.mode = typexpr
+                               x.typ = exp.typ
+                       case *Var:
+                               x.mode = variable
+                               x.typ = exp.typ
+                               if pkg.cgo && strings.HasPrefix(exp.name, "_Cvar_") {
+                                       x.typ = x.typ.(*Pointer).base
+                               }
+                       case *Func:
+                               x.mode = funcMode
+                               x.typ = exp.typ
+                               if pkg.cgo && strings.HasPrefix(exp.name, "_Cmacro_") {
+                                       x.mode = value
+                                       x.typ = x.typ.(*Signature).results.vars[0].typ
+                               }
+                       case *Builtin:
+                               x.mode = builtin
+                               x.typ = exp.typ
+                               x.id = exp.id
+                       default:
+                               check.dump("%v: unexpected object %v", posFor(e.Sel), exp)
+                               unreachable()
+                       }
+                       x.expr = e
+                       return
+               }
+       }
+
+       check.exprOrType(x, e.X)
+       if x.mode == invalid {
+               goto Error
+       }
+
+       check.instantiatedOperand(x)
+
+       obj, index, indirect = check.lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
+       if obj == nil {
+               switch {
+               case index != nil:
+                       // TODO(gri) should provide actual type where the conflict happens
+                       check.errorf(e.Sel, "ambiguous selector %s.%s", x.expr, sel)
+               case indirect:
+                       check.errorf(e.Sel, "cannot call pointer method %s on %s", sel, x.typ)
+               default:
+                       var why string
+                       if tpar := x.typ.TypeParam(); tpar != nil {
+                               // Type parameter bounds don't specify fields, so don't mention "field".
+                               switch obj := tpar.Bound().obj.(type) {
+                               case nil:
+                                       why = check.sprintf("type bound for %s has no method %s", x.typ, sel)
+                               case *TypeName:
+                                       why = check.sprintf("interface %s has no method %s", obj.name, sel)
+                               }
+                       } else {
+                               why = check.sprintf("type %s has no field or method %s", x.typ, sel)
+                       }
+
+                       // Check if capitalization of sel matters and provide better error message in that case.
+                       if len(sel) > 0 {
+                               var changeCase string
+                               if r := rune(sel[0]); unicode.IsUpper(r) {
+                                       changeCase = string(unicode.ToLower(r)) + sel[1:]
+                               } else {
+                                       changeCase = string(unicode.ToUpper(r)) + sel[1:]
+                               }
+                               if obj, _, _ = check.lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, changeCase); obj != nil {
+                                       why += ", but does have " + changeCase
+                               }
+                       }
+
+                       check.errorf(e.Sel, "%s.%s undefined (%s)", x.expr, sel, why)
+
+               }
+               goto Error
+       }
+
+       // methods may not have a fully set up signature yet
+       if m, _ := obj.(*Func); m != nil {
+               // check.dump("### found method %s", m)
+               check.objDecl(m, nil)
+               // If m has a parameterized receiver type, infer the type parameter
+               // values from the actual receiver provided and then substitute the
+               // type parameters in the signature accordingly.
+               // TODO(gri) factor this code out
+               sig := m.typ.(*Signature)
+               if len(sig.rparams) > 0 {
+                       //check.dump("### recv typ = %s", x.typ)
+                       //check.dump("### method = %s rparams = %s tparams = %s", m, sig.rparams, sig.tparams)
+                       // The method may have a pointer receiver, but the actually provided receiver
+                       // may be a (hopefully addressable) non-pointer value, or vice versa. Here we
+                       // only care about inferring receiver type parameters; to make the inference
+                       // work, match up pointer-ness of receiver and argument.
+                       arg := x
+                       if ptrRecv := isPointer(sig.recv.typ); ptrRecv != isPointer(arg.typ) {
+                               copy := *arg
+                               if ptrRecv {
+                                       copy.typ = NewPointer(arg.typ)
+                               } else {
+                                       copy.typ = arg.typ.(*Pointer).base
+                               }
+                               arg = &copy
+                       }
+                       targs, failed := check.infer(sig.rparams, NewTuple(sig.recv), []*operand{arg})
+                       //check.dump("### inferred targs = %s", targs)
+                       if failed >= 0 {
+                               // We may reach here if there were other errors (see issue #40056).
+                               // check.infer will report a follow-up error.
+                               // TODO(gri) avoid the follow-up error or provide better explanation.
+                               goto Error
+                       }
+                       // Don't modify m. Instead - for now - make a copy of m and use that instead.
+                       // (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, targs))
+                       obj = &copy
+               }
+               // TODO(gri) we also need to do substitution for parameterized interface methods
+               //           (this breaks code in testdata/linalg.go2 at the moment)
+               //           12/20/2019: Is this TODO still correct?
+       }
+
+       if x.mode == typexpr {
+               // method expression
+               m, _ := obj.(*Func)
+               if m == nil {
+                       // TODO(gri) should check if capitalization of sel matters and provide better error message in that case
+                       check.errorf(e.Sel, "%s.%s undefined (type %s has no method %s)", x.expr, sel, x.typ, sel)
+                       goto Error
+               }
+
+               check.recordSelection(e, MethodExpr, x.typ, m, index, indirect)
+
+               // the receiver type becomes the type of the first function
+               // argument of the method expression's function type
+               var params []*Var
+               sig := m.typ.(*Signature)
+               if sig.params != nil {
+                       params = sig.params.vars
+               }
+               x.mode = value
+               x.typ = &Signature{
+                       tparams:  sig.tparams,
+                       params:   NewTuple(append([]*Var{NewVar(nopos, check.pkg, "_", x.typ)}, params...)...),
+                       results:  sig.results,
+                       variadic: sig.variadic,
+               }
+
+               check.addDeclDep(m)
+
+       } else {
+               // regular selector
+               switch obj := obj.(type) {
+               case *Var:
+                       check.recordSelection(e, FieldVal, x.typ, obj, index, indirect)
+                       if x.mode == variable || indirect {
+                               x.mode = variable
+                       } else {
+                               x.mode = value
+                       }
+                       x.typ = obj.typ
+
+               case *Func:
+                       // TODO(gri) If we needed to take into account the receiver's
+                       // addressability, should we report the type &(x.typ) instead?
+                       check.recordSelection(e, MethodVal, x.typ, obj, index, indirect)
+
+                       // TODO(gri) The verification pass below is disabled for now because
+                       //           method sets don't match method lookup in some cases.
+                       //           For instance, if we made a copy above when creating a
+                       //           custom method for a parameterized received type, the
+                       //           method set method doesn't match (no copy there). There
+                       ///          may be other situations.
+                       disabled := true
+                       if !disabled && debug {
+                               // Verify that LookupFieldOrMethod and MethodSet.Lookup agree.
+                               // TODO(gri) This only works because we call LookupFieldOrMethod
+                               // _before_ calling NewMethodSet: LookupFieldOrMethod completes
+                               // any incomplete interfaces so they are available to NewMethodSet
+                               // (which assumes that interfaces have been completed already).
+                               typ := x.typ
+                               if x.mode == variable {
+                                       // If typ is not an (unnamed) pointer or an interface,
+                                       // use *typ instead, because the method set of *typ
+                                       // includes the methods of typ.
+                                       // Variables are addressable, so we can always take their
+                                       // address.
+                                       if _, ok := typ.(*Pointer); !ok && !IsInterface(typ) {
+                                               typ = &Pointer{base: typ}
+                                       }
+                               }
+                               // If we created a synthetic pointer type above, we will throw
+                               // away the method set computed here after use.
+                               // TODO(gri) Method set computation should probably always compute
+                               // both, the value and the pointer receiver method set and represent
+                               // them in a single structure.
+                               // TODO(gri) Consider also using a method set cache for the lifetime
+                               // of checker once we rely on MethodSet lookup instead of individual
+                               // lookup.
+                               mset := NewMethodSet(typ)
+                               if m := mset.Lookup(check.pkg, sel); m == nil || m.obj != obj {
+                                       check.dump("%v: (%s).%v -> %s", posFor(e), typ, obj.name, m)
+                                       check.dump("%s\n", mset)
+                                       // Caution: MethodSets are supposed to be used externally
+                                       // only (after all interface types were completed). It's
+                                       // now possible that we get here incorrectly. Not urgent
+                                       // to fix since we only run this code in debug mode.
+                                       // TODO(gri) fix this eventually.
+                                       panic("method sets and lookup don't agree")
+                               }
+                       }
+
+                       x.mode = value
+
+                       // remove receiver
+                       sig := *obj.typ.(*Signature)
+                       sig.recv = nil
+                       x.typ = &sig
+
+                       check.addDeclDep(obj)
+
+               default:
+                       unreachable()
+               }
+       }
+
+       // everything went well
+       x.expr = e
+       return
+
+Error:
+       x.mode = invalid
+       x.expr = e
+}
+
+// use type-checks each argument.
+// Useful to make sure expressions are evaluated
+// (and variables are "used") in the presence of other errors.
+// The arguments may be nil.
+// TODO(gri) make this accept a []syntax.Expr and use an unpack function when we have a ListExpr?
+func (check *Checker) use(arg ...syntax.Expr) {
+       var x operand
+       for _, e := range arg {
+               // Certain AST fields may legally be nil (e.g., the ast.SliceExpr.High field).
+               if e == nil {
+                       continue
+               }
+               if l, _ := e.(*syntax.ListExpr); l != nil {
+                       check.use(l.ElemList...)
+                       continue
+               }
+               check.rawExpr(&x, e, nil)
+       }
+}
+
+// useLHS is like use, but doesn't "use" top-level identifiers.
+// It should be called instead of use if the arguments are
+// expressions on the lhs of an assignment.
+// The arguments must not be nil.
+func (check *Checker) useLHS(arg ...syntax.Expr) {
+       var x operand
+       for _, e := range arg {
+               // If the lhs is an identifier denoting a variable v, this assignment
+               // is not a 'use' of v. Remember current value of v.used and restore
+               // after evaluating the lhs via check.rawExpr.
+               var v *Var
+               var v_used bool
+               if ident, _ := unparen(e).(*syntax.Name); ident != nil {
+                       // never type-check the blank name on the lhs
+                       if ident.Value == "_" {
+                               continue
+                       }
+                       if _, obj := check.scope.LookupParent(ident.Value, nopos); obj != nil {
+                               // It's ok to mark non-local variables, but ignore variables
+                               // from other packages to avoid potential race conditions with
+                               // dot-imported variables.
+                               if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
+                                       v = w
+                                       v_used = v.used
+                               }
+                       }
+               }
+               check.rawExpr(&x, e, nil)
+               if v != nil {
+                       v.used = v_used // restore v.used
+               }
+       }
+}
+
+// instantiatedOperand reports an error of x is an uninstantiated (generic) type and sets x.typ to Typ[Invalid].
+func (check *Checker) instantiatedOperand(x *operand) {
+       if x.mode == typexpr && isGeneric(x.typ) {
+               check.errorf(x, "cannot use generic type %s without instantiation", x.typ)
+               x.typ = Typ[Invalid]
+       }
+}
diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go
new file mode 100644 (file)
index 0000000..6ba8506
--- /dev/null
@@ -0,0 +1,450 @@
+// UNREVIEWED
+// Copyright 2011 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.
+
+// This file implements the Check function, which drives type-checking.
+
+package types2
+
+import (
+       "cmd/compile/internal/syntax"
+       "errors"
+       "fmt"
+       "go/constant"
+)
+
+var nopos syntax.Pos
+
+// debugging/development support
+const debug = true // leave on during development
+
+// If forceStrict is set, the type-checker enforces additional
+// rules not specified by the Go 1 spec, but which will
+// catch guaranteed run-time errors if the respective
+// code is executed. In other words, programs passing in
+// strict mode are Go 1 compliant, but not all Go 1 programs
+// will pass in strict mode. The additional rules are:
+//
+// - A type assertion x.(T) where T is an interface type
+//   is invalid if any (statically known) method that exists
+//   for both x and T have different signatures.
+//
+const forceStrict = false
+
+// If methodTypeParamsOk is set, type parameters are
+// permitted in method declarations (in interfaces, too).
+// Generalization and experimental feature.
+const methodTypeParamsOk = true
+
+// exprInfo stores information about an untyped expression.
+type exprInfo struct {
+       isLhs bool // expression is lhs operand of a shift with delayed type-check
+       mode  operandMode
+       typ   *Basic
+       val   constant.Value // constant value; or nil (if not a constant)
+}
+
+// A context represents the context within which an object is type-checked.
+type context struct {
+       decl          *declInfo                 // package-level declaration whose init expression/function body is checked
+       scope         *Scope                    // top-most scope for lookups
+       pos           syntax.Pos                // if valid, identifiers are looked up as if at position pos (used by Eval)
+       iota          constant.Value            // value of iota in a constant declaration; nil otherwise
+       errpos        syntax.Pos                // if valid, identifier position of a constant with inherited initializer
+       sig           *Signature                // function signature if inside a function; nil otherwise
+       isPanic       map[*syntax.CallExpr]bool // set of panic call expressions (used for termination check)
+       hasLabel      bool                      // set if a function makes use of labels (only ~1% of functions); unused outside functions
+       hasCallOrRecv bool                      // set if an expression contains a function call or channel receive operation
+}
+
+// lookup looks up name in the current context and returns the matching object, or nil.
+func (ctxt *context) lookup(name string) Object {
+       _, obj := ctxt.scope.LookupParent(name, ctxt.pos)
+       return obj
+}
+
+// An importKey identifies an imported package by import path and source directory
+// (directory containing the file containing the import). In practice, the directory
+// may always be the same, or may not matter. Given an (import path, directory), an
+// importer must always return the same package (but given two different import paths,
+// an importer may still return the same package by mapping them to the same package
+// paths).
+type importKey struct {
+       path, dir string
+}
+
+// A Checker maintains the state of the type checker.
+// It must be created with NewChecker.
+type Checker struct {
+       // package information
+       // (initialized by NewChecker, valid for the life-time of checker)
+       conf *Config
+       pkg  *Package
+       *Info
+       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
+       posMap map[*Interface][]syntax.Pos // maps interface types to lists of embedded interface positions
+       typMap map[string]*Named           // maps an instantiated named type hash to a *Named type
+       pkgCnt map[string]int              // counts number of imported packages with a given name (for better error messages)
+
+       // information collected during type-checking of a set of package files
+       // (initialized by Files, valid only for the duration of check.Files;
+       // maps and lists are allocated on demand)
+       files            []*syntax.File                     // package files
+       unusedDotImports map[*Scope]map[*Package]syntax.Pos // positions of unused dot-imported packages for each file scope
+
+       firstErr error                    // first error encountered
+       methods  map[*TypeName][]*Func    // maps package scope type names to associated non-blank (non-interface) methods
+       untyped  map[syntax.Expr]exprInfo // map of expressions without final type
+       delayed  []func()                 // stack of delayed action segments; segments are processed in FIFO order
+       finals   []func()                 // list of final actions; processed at the end of type-checking the current set of files
+       objPath  []Object                 // path of object dependencies during type inference (for cycle reporting)
+
+       // context within which the current object is type-checked
+       // (valid only for the duration of type-checking a specific object)
+       context
+
+       // debugging
+       indent int // indentation for tracing
+}
+
+// addUnusedImport adds the position of a dot-imported package
+// pkg to the map of dot imports for the given file scope.
+func (check *Checker) addUnusedDotImport(scope *Scope, pkg *Package, pos syntax.Pos) {
+       mm := check.unusedDotImports
+       if mm == nil {
+               mm = make(map[*Scope]map[*Package]syntax.Pos)
+               check.unusedDotImports = mm
+       }
+       m := mm[scope]
+       if m == nil {
+               m = make(map[*Package]syntax.Pos)
+               mm[scope] = m
+       }
+       m[pkg] = pos
+}
+
+// addDeclDep adds the dependency edge (check.decl -> to) if check.decl exists
+func (check *Checker) addDeclDep(to Object) {
+       from := check.decl
+       if from == nil {
+               return // not in a package-level init expression
+       }
+       if _, found := check.objMap[to]; !found {
+               return // to is not a package-level object
+       }
+       from.addDep(to)
+}
+
+func (check *Checker) rememberUntyped(e syntax.Expr, lhs bool, mode operandMode, typ *Basic, val constant.Value) {
+       m := check.untyped
+       if m == nil {
+               m = make(map[syntax.Expr]exprInfo)
+               check.untyped = m
+       }
+       m[e] = exprInfo{lhs, mode, typ, val}
+}
+
+// later pushes f on to the stack of actions that will be processed later;
+// either at the end of the current statement, or in case of a local constant
+// or variable declaration, before the constant or variable is in scope
+// (so that f still sees the scope before any new declarations).
+func (check *Checker) later(f func()) {
+       check.delayed = append(check.delayed, f)
+}
+
+// atEnd adds f to the list of actions processed at the end
+// of type-checking, before initialization order computation.
+// Actions added by atEnd are processed after any actions
+// added by later.
+func (check *Checker) atEnd(f func()) {
+       check.finals = append(check.finals, f)
+}
+
+// push pushes obj onto the object path and returns its index in the path.
+func (check *Checker) push(obj Object) int {
+       check.objPath = append(check.objPath, obj)
+       return len(check.objPath) - 1
+}
+
+// pop pops and returns the topmost object from the object path.
+func (check *Checker) pop() Object {
+       i := len(check.objPath) - 1
+       obj := check.objPath[i]
+       check.objPath[i] = nil
+       check.objPath = check.objPath[:i]
+       return obj
+}
+
+// NewChecker returns a new Checker instance for a given package.
+// Package files may be added incrementally via checker.Files.
+func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
+       // make sure we have a configuration
+       if conf == nil {
+               conf = new(Config)
+       }
+
+       // make sure we have an info struct
+       if info == nil {
+               info = new(Info)
+       }
+
+       return &Checker{
+               conf:   conf,
+               pkg:    pkg,
+               Info:   info,
+               nextId: 1,
+               objMap: make(map[Object]*declInfo),
+               impMap: make(map[importKey]*Package),
+               posMap: make(map[*Interface][]syntax.Pos),
+               typMap: make(map[string]*Named),
+               pkgCnt: make(map[string]int),
+       }
+}
+
+// initFiles initializes the files-specific portion of checker.
+// The provided files must all belong to the same package.
+func (check *Checker) initFiles(files []*syntax.File) {
+       // start with a clean slate (check.Files may be called multiple times)
+       check.files = nil
+       check.unusedDotImports = nil
+
+       check.firstErr = nil
+       check.methods = nil
+       check.untyped = nil
+       check.delayed = nil
+       check.finals = nil
+
+       // determine package name and collect valid files
+       pkg := check.pkg
+       for _, file := range files {
+               switch name := file.PkgName.Value; pkg.name {
+               case "":
+                       if name != "_" {
+                               pkg.name = name
+                       } else {
+                               check.errorf(file.PkgName, "invalid package name _")
+                       }
+                       fallthrough
+
+               case name:
+                       check.files = append(check.files, file)
+
+               default:
+                       check.errorf(file, "package %s; expected %s", name, pkg.name)
+                       // ignore this file
+               }
+       }
+}
+
+// A bailout panic is used for early termination.
+type bailout struct{}
+
+func (check *Checker) handleBailout(err *error) {
+       switch p := recover().(type) {
+       case nil, bailout:
+               // normal return or early exit
+               *err = check.firstErr
+       default:
+               // re-panic
+               panic(p)
+       }
+}
+
+// Files checks the provided files as part of the checker's package.
+func (check *Checker) Files(files []*syntax.File) error { return check.checkFiles(files) }
+
+var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
+
+func (check *Checker) checkFiles(files []*syntax.File) (err error) {
+       if check.conf.FakeImportC && check.conf.go115UsesCgo {
+               return errBadCgo
+       }
+
+       defer check.handleBailout(&err)
+
+       print := func(msg string) {
+               if check.conf.Trace {
+                       fmt.Println(msg)
+               }
+       }
+
+       print("== initFiles ==")
+       check.initFiles(files)
+
+       print("== collectObjects ==")
+       check.collectObjects()
+
+       print("== packageObjects ==")
+       check.packageObjects()
+
+       print("== processDelayed ==")
+       check.processDelayed(0) // incl. all functions
+       check.processFinals()
+
+       print("== initOrder ==")
+       check.initOrder()
+
+       if !check.conf.DisableUnusedImportCheck {
+               print("== unusedImports ==")
+               check.unusedImports()
+       }
+
+       print("== recordUntyped ==")
+       check.recordUntyped()
+
+       if check.Info != nil {
+               print("== sanitizeInfo ==")
+               sanitizeInfo(check.Info)
+       }
+
+       check.pkg.complete = true
+       return
+}
+
+// processDelayed processes all delayed actions pushed after top.
+func (check *Checker) processDelayed(top int) {
+       // If each delayed action pushes a new action, the
+       // stack will continue to grow during this loop.
+       // However, it is only processing functions (which
+       // are processed in a delayed fashion) that may
+       // add more actions (such as nested functions), so
+       // this is a sufficiently bounded process.
+       for i := top; i < len(check.delayed); i++ {
+               check.delayed[i]() // may append to check.delayed
+       }
+       assert(top <= len(check.delayed)) // stack must not have shrunk
+       check.delayed = check.delayed[:top]
+}
+
+func (check *Checker) processFinals() {
+       n := len(check.finals)
+       for _, f := range check.finals {
+               f() // must not append to check.finals
+       }
+       if len(check.finals) != n {
+               panic("internal error: final action list grew")
+       }
+}
+
+func (check *Checker) recordUntyped() {
+       if !debug && check.Types == nil {
+               return // nothing to do
+       }
+
+       for x, info := range check.untyped {
+               if debug && isTyped(info.typ) {
+                       check.dump("%v: %s (type %s) is typed", posFor(x), x, info.typ)
+                       unreachable()
+               }
+               check.recordTypeAndValue(x, info.mode, info.typ, info.val)
+       }
+}
+
+func (check *Checker) recordTypeAndValue(x syntax.Expr, mode operandMode, typ Type, val constant.Value) {
+       assert(x != nil)
+       assert(typ != nil)
+       if mode == invalid {
+               return // omit
+       }
+       if mode == constant_ {
+               assert(val != nil)
+               assert(typ == Typ[Invalid] || isConstType(typ))
+       }
+       if m := check.Types; m != nil {
+               m[x] = TypeAndValue{mode, typ, val}
+       }
+}
+
+func (check *Checker) recordBuiltinType(f syntax.Expr, sig *Signature) {
+       // f must be a (possibly parenthesized) identifier denoting a built-in
+       // (built-ins in package unsafe always produce a constant result and
+       // we don't record their signatures, so we don't see qualified idents
+       // here): record the signature for f and possible children.
+       for {
+               check.recordTypeAndValue(f, builtin, sig, nil)
+               switch p := f.(type) {
+               case *syntax.Name:
+                       return // we're done
+               case *syntax.ParenExpr:
+                       f = p.X
+               default:
+                       unreachable()
+               }
+       }
+}
+
+func (check *Checker) recordCommaOkTypes(x syntax.Expr, a [2]Type) {
+       assert(x != nil)
+       if a[0] == nil || a[1] == nil {
+               return
+       }
+       assert(isTyped(a[0]) && isTyped(a[1]) && (isBoolean(a[1]) || a[1] == universeError))
+       if m := check.Types; m != nil {
+               for {
+                       tv := m[x]
+                       assert(tv.Type != nil) // should have been recorded already
+                       pos := x.Pos()
+                       tv.Type = NewTuple(
+                               NewVar(pos, check.pkg, "", a[0]),
+                               NewVar(pos, check.pkg, "", a[1]),
+                       )
+                       m[x] = tv
+                       // if x is a parenthesized expression (p.X), update p.X
+                       p, _ := x.(*syntax.ParenExpr)
+                       if p == nil {
+                               break
+                       }
+                       x = p.X
+               }
+       }
+}
+
+func (check *Checker) recordInferred(call syntax.Expr, targs []Type, sig *Signature) {
+       assert(call != nil)
+       assert(sig != nil)
+       if m := check.Inferred; m != nil {
+               m[call] = Inferred{targs, sig}
+       }
+}
+
+func (check *Checker) recordDef(id *syntax.Name, obj Object) {
+       assert(id != nil)
+       if m := check.Defs; m != nil {
+               m[id] = obj
+       }
+}
+
+func (check *Checker) recordUse(id *syntax.Name, obj Object) {
+       assert(id != nil)
+       assert(obj != nil)
+       if m := check.Uses; m != nil {
+               m[id] = obj
+       }
+}
+
+func (check *Checker) recordImplicit(node syntax.Node, obj Object) {
+       assert(node != nil)
+       assert(obj != nil)
+       if m := check.Implicits; m != nil {
+               m[node] = obj
+       }
+}
+
+func (check *Checker) recordSelection(x *syntax.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
+       assert(obj != nil && (recv == nil || len(index) > 0))
+       check.recordUse(x.Sel, obj)
+       if m := check.Selections; m != nil {
+               m[x] = &Selection{kind, recv, obj, index, indirect}
+       }
+}
+
+func (check *Checker) recordScope(node syntax.Node, scope *Scope) {
+       assert(node != nil)
+       assert(scope != nil)
+       if m := check.Scopes; m != nil {
+               m[node] = scope
+       }
+}
diff --git a/src/cmd/compile/internal/types2/check_test.go b/src/cmd/compile/internal/types2/check_test.go
new file mode 100644 (file)
index 0000000..85bf072
--- /dev/null
@@ -0,0 +1,268 @@
+// UNREVIEWED
+// Copyright 2011 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.
+
+// This file implements a typechecker test harness. The packages specified
+// in tests are typechecked. Error messages reported by the typechecker are
+// compared against the error messages expected in the test files.
+//
+// Expected errors are indicated in the test files by putting a comment
+// of the form /* ERROR "rx" */ immediately following an offending token.
+// The harness will verify that an error matching the regular expression
+// rx is reported at that source position. Consecutive comments may be
+// used to indicate multiple errors for the same token position.
+//
+// For instance, the following test file indicates that a "not declared"
+// error should be reported for the undeclared variable x:
+//
+//     package p
+//     func f() {
+//             _ = x /* ERROR "not declared" */ + 1
+//     }
+
+// TODO(gri) Also collect strict mode errors of the form /* STRICT ... */
+//           and test against strict mode.
+
+package types2_test
+
+import (
+       "cmd/compile/internal/syntax"
+       "flag"
+       "fmt"
+       "internal/testenv"
+       "io/ioutil"
+       "os"
+       "path/filepath"
+       "regexp"
+       "strings"
+       "testing"
+
+       . "cmd/compile/internal/types2"
+)
+
+var (
+       haltOnError = flag.Bool("halt", false, "halt on error")
+       listErrors  = flag.Bool("errlist", false, "list errors")
+       testFiles   = flag.String("files", "", "space-separated list of test files")
+)
+
+func parseFiles(t *testing.T, filenames []string) ([]*syntax.File, []error) {
+       var files []*syntax.File
+       var errlist []error
+       errh := func(err error) { errlist = append(errlist, err) }
+       for _, filename := range filenames {
+               file, err := syntax.ParseFile(filename, errh, nil, syntax.AllowGenerics)
+               if file == nil {
+                       t.Fatalf("%s: %s", filename, err)
+               }
+               files = append(files, file)
+       }
+       return files, errlist
+}
+
+func unpackError(err error) syntax.Error {
+       switch err := err.(type) {
+       case syntax.Error:
+               return err
+       case Error:
+               return syntax.Error{Pos: err.Pos, Msg: err.Msg}
+       default:
+               return syntax.Error{Msg: err.Error()}
+       }
+}
+
+func delta(x, y uint) uint {
+       switch {
+       case x < y:
+               return y - x
+       case x > y:
+               return x - y
+       default:
+               return 0
+       }
+}
+
+func checkFiles(t *testing.T, sources []string, colDelta uint, trace bool) {
+       // parse files and collect parser errors
+       files, errlist := parseFiles(t, sources)
+
+       pkgName := "<no package>"
+       if len(files) > 0 {
+               pkgName = files[0].PkgName.Value
+       }
+
+       if *listErrors && len(errlist) > 0 {
+               t.Errorf("--- %s:", pkgName)
+               for _, err := range errlist {
+                       t.Error(err)
+               }
+       }
+
+       // typecheck and collect typechecker errors
+       var conf Config
+       conf.AcceptMethodTypeParams = true
+       conf.InferFromConstraints = true
+       // special case for importC.src
+       if len(sources) == 1 && strings.HasSuffix(sources[0], "importC.src") {
+               conf.FakeImportC = true
+       }
+       conf.Trace = trace
+       conf.Importer = defaultImporter()
+       conf.Error = func(err error) {
+               if *haltOnError {
+                       defer panic(err)
+               }
+               if *listErrors {
+                       t.Error(err)
+                       return
+               }
+               // Ignore secondary error messages starting with "\t";
+               // they are clarifying messages for a primary error.
+               if !strings.Contains(err.Error(), ": \t") {
+                       errlist = append(errlist, err)
+               }
+       }
+       conf.Check(pkgName, files, nil)
+
+       if *listErrors {
+               return
+       }
+
+       // collect expected errors
+       errmap := make(map[string]map[uint][]syntax.Error)
+       for _, filename := range sources {
+               f, err := os.Open(filename)
+               if err != nil {
+                       t.Error(err)
+                       continue
+               }
+               if m := syntax.ErrorMap(f); len(m) > 0 {
+                       errmap[filename] = m
+               }
+               f.Close()
+       }
+
+       // match against found errors
+       for _, err := range errlist {
+               got := unpackError(err)
+
+               // find list of errors for the respective error line
+               filename := got.Pos.Base().Filename()
+               filemap := errmap[filename]
+               var line uint
+               var list []syntax.Error
+               if filemap != nil {
+                       line = got.Pos.Line()
+                       list = filemap[line]
+               }
+               // list may be nil
+
+               // one of errors in list should match the current error
+               index := -1 // list index of matching message, if any
+               for i, want := range list {
+                       rx, err := regexp.Compile(want.Msg)
+                       if err != nil {
+                               t.Errorf("%s:%d:%d: %v", filename, line, want.Pos.Col(), err)
+                               continue
+                       }
+                       if rx.MatchString(got.Msg) {
+                               index = i
+                               break
+                       }
+               }
+               if index < 0 {
+                       t.Errorf("%s: no error expected: %q", got.Pos, got.Msg)
+                       continue
+               }
+
+               // column position must be within expected colDelta
+               want := list[index]
+               if delta(got.Pos.Col(), want.Pos.Col()) > colDelta {
+                       t.Errorf("%s: got col = %d; want %d", got.Pos, got.Pos.Col(), want.Pos.Col())
+               }
+
+               // eliminate from list
+               if n := len(list) - 1; n > 0 {
+                       // not the last entry - swap in last element and shorten list by 1
+                       list[index] = list[n]
+                       filemap[line] = list[:n]
+               } else {
+                       // last entry - remove list from filemap
+                       delete(filemap, line)
+               }
+
+               // if filemap is empty, eliminate from errmap
+               if len(filemap) == 0 {
+                       delete(errmap, filename)
+               }
+       }
+
+       // there should be no expected errors left
+       if len(errmap) > 0 {
+               t.Errorf("--- %s: unreported errors:", pkgName)
+               for filename, filemap := range errmap {
+                       for line, list := range filemap {
+                               for _, err := range list {
+                                       t.Errorf("%s:%d:%d: %s", filename, line, err.Pos.Col(), err.Msg)
+                               }
+                       }
+               }
+       }
+}
+
+// TestCheck is for manual testing of selected input files, provided with -files.
+func TestCheck(t *testing.T) {
+       if *testFiles == "" {
+               return
+       }
+       testenv.MustHaveGoBuild(t)
+       DefPredeclaredTestFuncs()
+       checkFiles(t, strings.Split(*testFiles, " "), 0, testing.Verbose())
+}
+
+func TestTestdata(t *testing.T)  { DefPredeclaredTestFuncs(); testDir(t, 75, "testdata") } // TODO(gri) narrow column tolerance
+func TestExamples(t *testing.T)  { testDir(t, 0, "examples") }
+func TestFixedbugs(t *testing.T) { testDir(t, 0, "fixedbugs") }
+
+func testDir(t *testing.T, colDelta uint, dir string) {
+       testenv.MustHaveGoBuild(t)
+
+       fis, err := ioutil.ReadDir(dir)
+       if err != nil {
+               t.Error(err)
+               return
+       }
+
+       for count, fi := range fis {
+               path := filepath.Join(dir, fi.Name())
+
+               // if fi is a directory, its files make up a single package
+               if fi.IsDir() {
+                       if testing.Verbose() {
+                               fmt.Printf("%3d %s\n", count, path)
+                       }
+                       fis, err := ioutil.ReadDir(path)
+                       if err != nil {
+                               t.Error(err)
+                               continue
+                       }
+                       files := make([]string, len(fis))
+                       for i, fi := range fis {
+                               // if fi is a directory, checkFiles below will complain
+                               files[i] = filepath.Join(path, fi.Name())
+                               if testing.Verbose() {
+                                       fmt.Printf("\t%s\n", files[i])
+                               }
+                       }
+                       checkFiles(t, files, colDelta, false)
+                       continue
+               }
+
+               // otherwise, fi is a stand-alone file
+               if testing.Verbose() {
+                       fmt.Printf("%3d %s\n", count, path)
+               }
+               checkFiles(t, []string{path}, colDelta, false)
+       }
+}
diff --git a/src/cmd/compile/internal/types2/conversions.go b/src/cmd/compile/internal/types2/conversions.go
new file mode 100644 (file)
index 0000000..0f6a990
--- /dev/null
@@ -0,0 +1,164 @@
+// UNREVIEWED
+// Copyright 2012 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.
+
+// This file implements typechecking of conversions.
+
+package types2
+
+import (
+       "go/constant"
+       "unicode"
+)
+
+// Conversion type-checks the conversion T(x).
+// The result is in x.
+func (check *Checker) conversion(x *operand, T Type) {
+       constArg := x.mode == constant_
+
+       var ok bool
+       switch {
+       case constArg && isConstType(T):
+               // constant conversion
+               switch t := T.Basic(); {
+               case representableConst(x.val, check, t, &x.val):
+                       ok = true
+               case isInteger(x.typ) && isString(t):
+                       codepoint := unicode.ReplacementChar
+                       if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune {
+                               codepoint = rune(i)
+                       }
+                       x.val = constant.MakeString(string(codepoint))
+                       ok = true
+               }
+       case x.convertibleTo(check, T):
+               // non-constant conversion
+               x.mode = value
+               ok = true
+       }
+
+       if !ok {
+               check.errorf(x, "cannot convert %s to %s", x, T)
+               x.mode = invalid
+               return
+       }
+
+       // The conversion argument types are final. For untyped values the
+       // conversion provides the type, per the spec: "A constant may be
+       // given a type explicitly by a constant declaration or conversion,...".
+       if isUntyped(x.typ) {
+               final := T
+               // - For conversions to interfaces, use the argument's default type.
+               // - For conversions of untyped constants to non-constant types, also
+               //   use the default type (e.g., []byte("foo") should report string
+               //   not []byte as type for the constant "foo").
+               // - Keep untyped nil for untyped nil arguments.
+               // - For integer to string conversions, keep the argument type.
+               //   (See also the TODO below.)
+               if IsInterface(T) || constArg && !isConstType(T) {
+                       final = Default(x.typ)
+               } else if isInteger(x.typ) && isString(T) {
+                       final = x.typ
+               }
+               check.updateExprType(x.expr, final, true)
+       }
+
+       x.typ = T
+}
+
+// TODO(gri) convertibleTo checks if T(x) is valid. It assumes that the type
+// of x is fully known, but that's not the case for say string(1<<s + 1.0):
+// Here, the type of 1<<s + 1.0 will be UntypedFloat which will lead to the
+// (correct!) refusal of the conversion. But the reported error is essentially
+// "cannot convert untyped float value to string", yet the correct error (per
+// the spec) is that we cannot shift a floating-point value: 1 in 1<<s should
+// be converted to UntypedFloat because of the addition of 1.0. Fixing this
+// is tricky because we'd have to run updateExprType on the argument first.
+// (Issue #21982.)
+
+// convertibleTo reports whether T(x) is valid.
+// The check parameter may be nil if convertibleTo is invoked through an
+// exported API call, i.e., when all methods have been type-checked.
+func (x *operand) convertibleTo(check *Checker, T Type) bool {
+       // "x is assignable to T"
+       if x.assignableTo(check, T, nil) {
+               return true
+       }
+
+       // "x's type and T have identical underlying types if tags are ignored"
+       V := x.typ
+       Vu := V.Under()
+       Tu := T.Under()
+       if check.identicalIgnoreTags(Vu, Tu) {
+               return true
+       }
+
+       // "x's type and T are unnamed pointer types and their pointer base types
+       // have identical underlying types if tags are ignored"
+       if V, ok := V.(*Pointer); ok {
+               if T, ok := T.(*Pointer); ok {
+                       if check.identicalIgnoreTags(V.base.Under(), T.base.Under()) {
+                               return true
+                       }
+               }
+       }
+
+       // "x's type and T are both integer or floating point types"
+       if isIntegerOrFloat(V) && isIntegerOrFloat(T) {
+               return true
+       }
+
+       // "x's type and T are both complex types"
+       if isComplex(V) && isComplex(T) {
+               return true
+       }
+
+       // "x is an integer or a slice of bytes or runes and T is a string type"
+       if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) {
+               return true
+       }
+
+       // "x is a string and T is a slice of bytes or runes"
+       if isString(V) && isBytesOrRunes(Tu) {
+               return true
+       }
+
+       // package unsafe:
+       // "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer"
+       if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) {
+               return true
+       }
+       // "and vice versa"
+       if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) {
+               return true
+       }
+
+       return false
+}
+
+func isUintptr(typ Type) bool {
+       t := typ.Basic()
+       return t != nil && t.kind == Uintptr
+}
+
+func isUnsafePointer(typ Type) bool {
+       // TODO(gri): Is this typ.Basic() instead of typ.(*Basic) correct?
+       //            (The former calls typ.Under(), while the latter doesn't.)
+       //            The spec does not say so, but gc claims it is. See also
+       //            issue 6326.
+       t := typ.Basic()
+       return t != nil && t.kind == UnsafePointer
+}
+
+func isPointer(typ Type) bool {
+       return typ.Pointer() != nil
+}
+
+func isBytesOrRunes(typ Type) bool {
+       if s := typ.Slice(); s != nil {
+               t := s.elem.Basic()
+               return t != nil && (t.kind == Byte || t.kind == Rune)
+       }
+       return false
+}
diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go
new file mode 100644 (file)
index 0000000..0b7956f
--- /dev/null
@@ -0,0 +1,973 @@
+// UNREVIEWED
+// Copyright 2014 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 (
+       "cmd/compile/internal/syntax"
+       "fmt"
+       "go/constant"
+)
+
+func (check *Checker) reportAltDecl(obj Object) {
+       if pos := obj.Pos(); pos.IsKnown() {
+               // We use "other" rather than "previous" here because
+               // the first declaration seen may not be textually
+               // earlier in the source.
+               check.errorf(pos, "\tother declaration of %s", obj.Name()) // secondary error, \t indented
+       }
+}
+
+func (check *Checker) declare(scope *Scope, id *syntax.Name, obj Object, pos syntax.Pos) {
+       // spec: "The blank identifier, represented by the underscore
+       // character _, may be used in a declaration like any other
+       // identifier but the declaration does not introduce a new
+       // binding."
+       if obj.Name() != "_" {
+               if alt := scope.Insert(obj); alt != nil {
+                       check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
+                       check.reportAltDecl(alt)
+                       return
+               }
+               obj.setScopePos(pos)
+       }
+       if id != nil {
+               check.recordDef(id, obj)
+       }
+}
+
+// pathString returns a string of the form a->b-> ... ->g for a path [a, b, ... g].
+func pathString(path []Object) string {
+       var s string
+       for i, p := range path {
+               if i > 0 {
+                       s += "->"
+               }
+               s += p.Name()
+       }
+       return s
+}
+
+// objDecl type-checks the declaration of obj in its respective (file) context.
+// For the meaning of def, see Checker.definedType, in typexpr.go.
+func (check *Checker) objDecl(obj Object, def *Named) {
+       if check.conf.Trace && obj.Type() == nil {
+               if check.indent == 0 {
+                       fmt.Println() // empty line between top-level objects for readability
+               }
+               check.trace(obj.Pos(), "-- checking %s (%s, objPath = %s)", obj, obj.color(), pathString(check.objPath))
+               check.indent++
+               defer func() {
+                       check.indent--
+                       check.trace(obj.Pos(), "=> %s (%s)", obj, obj.color())
+               }()
+       }
+
+       // Checking the declaration of obj means inferring its type
+       // (and possibly its value, for constants).
+       // An object's type (and thus the object) may be in one of
+       // three states which are expressed by colors:
+       //
+       // - an object whose type is not yet known is painted white (initial color)
+       // - an object whose type is in the process of being inferred is painted grey
+       // - an object whose type is fully inferred is painted black
+       //
+       // During type inference, an object's color changes from white to grey
+       // to black (pre-declared objects are painted black from the start).
+       // A black object (i.e., its type) can only depend on (refer to) other black
+       // ones. White and grey objects may depend on white and black objects.
+       // A dependency on a grey object indicates a cycle which may or may not be
+       // valid.
+       //
+       // When objects turn grey, they are pushed on the object path (a stack);
+       // they are popped again when they turn black. Thus, if a grey object (a
+       // cycle) is encountered, it is on the object path, and all the objects
+       // it depends on are the remaining objects on that path. Color encoding
+       // is such that the color value of a grey object indicates the index of
+       // that object in the object path.
+
+       // During type-checking, white objects may be assigned a type without
+       // traversing through objDecl; e.g., when initializing constants and
+       // variables. Update the colors of those objects here (rather than
+       // everywhere where we set the type) to satisfy the color invariants.
+       if obj.color() == white && obj.Type() != nil {
+               obj.setColor(black)
+               return
+       }
+
+       switch obj.color() {
+       case white:
+               assert(obj.Type() == nil)
+               // All color values other than white and black are considered grey.
+               // Because black and white are < grey, all values >= grey are grey.
+               // Use those values to encode the object's index into the object path.
+               obj.setColor(grey + color(check.push(obj)))
+               defer func() {
+                       check.pop().setColor(black)
+               }()
+
+       case black:
+               assert(obj.Type() != nil)
+               return
+
+       default:
+               // Color values other than white or black are considered grey.
+               fallthrough
+
+       case grey:
+               // We have a cycle.
+               // In the existing code, this is marked by a non-nil type
+               // for the object except for constants and variables whose
+               // type may be non-nil (known), or nil if it depends on the
+               // not-yet known initialization value.
+               // In the former case, set the type to Typ[Invalid] because
+               // we have an initialization cycle. The cycle error will be
+               // reported later, when determining initialization order.
+               // TODO(gri) Report cycle here and simplify initialization
+               // order code.
+               switch obj := obj.(type) {
+               case *Const:
+                       if check.cycle(obj) || obj.typ == nil {
+                               obj.typ = Typ[Invalid]
+                       }
+
+               case *Var:
+                       if check.cycle(obj) || obj.typ == nil {
+                               obj.typ = Typ[Invalid]
+                       }
+
+               case *TypeName:
+                       if check.cycle(obj) {
+                               // break cycle
+                               // (without this, calling underlying()
+                               // below may lead to an endless loop
+                               // if we have a cycle for a defined
+                               // (*Named) type)
+                               obj.typ = Typ[Invalid]
+                       }
+
+               case *Func:
+                       if check.cycle(obj) {
+                               // Don't set obj.typ to Typ[Invalid] here
+                               // because plenty of code type-asserts that
+                               // functions have a *Signature type. Grey
+                               // functions have their type set to an empty
+                               // signature which makes it impossible to
+                               // initialize a variable with the function.
+                       }
+
+               default:
+                       unreachable()
+               }
+               assert(obj.Type() != nil)
+               return
+       }
+
+       d := check.objMap[obj]
+       if d == nil {
+               check.dump("%v: %s should have been declared", obj.Pos(), obj)
+               unreachable()
+       }
+
+       // save/restore current context and setup object context
+       defer func(ctxt context) {
+               check.context = ctxt
+       }(check.context)
+       check.context = context{
+               scope: d.file,
+       }
+
+       // Const and var declarations must not have initialization
+       // cycles. We track them by remembering the current declaration
+       // in check.decl. Initialization expressions depending on other
+       // consts, vars, or functions, add dependencies to the current
+       // check.decl.
+       switch obj := obj.(type) {
+       case *Const:
+               check.decl = d // new package-level const decl
+               check.constDecl(obj, d.vtyp, d.init, d.inherited)
+       case *Var:
+               check.decl = d // new package-level var decl
+               check.varDecl(obj, d.lhs, d.vtyp, d.init)
+       case *TypeName:
+               // invalid recursive types are detected via path
+               check.typeDecl(obj, d.tdecl, def)
+               check.collectMethods(obj) // methods can only be added to top-level types
+       case *Func:
+               // functions may be recursive - no need to track dependencies
+               check.funcDecl(obj, d)
+       default:
+               unreachable()
+       }
+}
+
+// cycle checks if the cycle starting with obj is valid and
+// reports an error if it is not.
+func (check *Checker) cycle(obj Object) (isCycle bool) {
+       // The object map contains the package scope objects and the non-interface methods.
+       if debug {
+               info := check.objMap[obj]
+               inObjMap := info != nil && (info.fdecl == nil || info.fdecl.Recv == nil) // exclude methods
+               isPkgObj := obj.Parent() == check.pkg.scope
+               if isPkgObj != inObjMap {
+                       check.dump("%v: inconsistent object map for %s (isPkgObj = %v, inObjMap = %v)", obj.Pos(), obj, isPkgObj, inObjMap)
+                       unreachable()
+               }
+       }
+
+       // Count cycle objects.
+       assert(obj.color() >= grey)
+       start := obj.color() - grey // index of obj in objPath
+       cycle := check.objPath[start:]
+       nval := 0 // number of (constant or variable) values in the cycle
+       ndef := 0 // number of type definitions in the cycle
+       for _, obj := range cycle {
+               switch obj := obj.(type) {
+               case *Const, *Var:
+                       nval++
+               case *TypeName:
+                       // Determine if the type name is an alias or not. For
+                       // package-level objects, use the object map which
+                       // provides syntactic information (which doesn't rely
+                       // on the order in which the objects are set up). For
+                       // local objects, we can rely on the order, so use
+                       // the object's predicate.
+                       // TODO(gri) It would be less fragile to always access
+                       // the syntactic information. We should consider storing
+                       // this information explicitly in the object.
+                       var alias bool
+                       if d := check.objMap[obj]; d != nil {
+                               alias = d.tdecl.Alias // package-level object
+                       } else {
+                               alias = obj.IsAlias() // function local object
+                       }
+                       if !alias {
+                               ndef++
+                       }
+               case *Func:
+                       // ignored for now
+               default:
+                       unreachable()
+               }
+       }
+
+       if check.conf.Trace {
+               check.trace(obj.Pos(), "## cycle detected: objPath = %s->%s (len = %d)", pathString(cycle), obj.Name(), len(cycle))
+               check.trace(obj.Pos(), "## cycle contains: %d values, %d type definitions", nval, ndef)
+               defer func() {
+                       if isCycle {
+                               check.trace(obj.Pos(), "=> error: cycle is invalid")
+                       }
+               }()
+       }
+
+       // A cycle involving only constants and variables is invalid but we
+       // ignore them here because they are reported via the initialization
+       // cycle check.
+       if nval == len(cycle) {
+               return false
+       }
+
+       // A cycle involving only types (and possibly functions) must have at least
+       // one type definition to be permitted: If there is no type definition, we
+       // have a sequence of alias type names which will expand ad infinitum.
+       if nval == 0 && ndef > 0 {
+               return false // cycle is permitted
+       }
+
+       check.cycleError(cycle)
+
+       return true
+}
+
+type typeInfo uint
+
+// validType verifies that the given type does not "expand" infinitely
+// producing a cycle in the type graph. Cycles are detected by marking
+// defined types.
+// (Cycles involving alias types, as in "type A = [10]A" are detected
+// earlier, via the objDecl cycle detection mechanism.)
+func (check *Checker) validType(typ Type, path []Object) typeInfo {
+       const (
+               unknown typeInfo = iota
+               marked
+               valid
+               invalid
+       )
+
+       switch t := typ.(type) {
+       case *Array:
+               return check.validType(t.elem, path)
+
+       case *Struct:
+               for _, f := range t.fields {
+                       if check.validType(f.typ, path) == invalid {
+                               return invalid
+                       }
+               }
+
+       case *Interface:
+               for _, etyp := range t.embeddeds {
+                       if check.validType(etyp, path) == invalid {
+                               return invalid
+                       }
+               }
+
+       case *Named:
+               // 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)
+               if t.obj.pkg != check.pkg {
+                       return valid
+               }
+
+               // don't report a 2nd error if we already know the type is invalid
+               // (e.g., if a cycle was detected earlier, via Checker.underlying).
+               if t.underlying == Typ[Invalid] {
+                       t.info = invalid
+                       return invalid
+               }
+
+               switch t.info {
+               case unknown:
+                       t.info = marked
+                       t.info = check.validType(t.orig, append(path, t.obj)) // only types of current package added to path
+               case marked:
+                       // cycle detected
+                       for i, tn := range path {
+                               if t.obj.pkg != check.pkg {
+                                       panic("internal error: type cycle via package-external type")
+                               }
+                               if tn == t.obj {
+                                       check.cycleError(path[i:])
+                                       t.info = invalid
+                                       return t.info
+                               }
+                       }
+                       panic("internal error: cycle start not found")
+               }
+               return t.info
+
+       case *instance:
+               return check.validType(t.expand(), path)
+       }
+
+       return valid
+}
+
+// cycleError reports a declaration cycle starting with
+// the object in cycle that is "first" in the source.
+func (check *Checker) cycleError(cycle []Object) {
+       // TODO(gri) Should we start with the last (rather than the first) object in the cycle
+       //           since that is the earliest point in the source where we start seeing the
+       //           cycle? That would be more consistent with other error messages.
+       i := firstInSrc(cycle)
+       obj := cycle[i]
+       if check.conf.CompilerErrorMessages {
+               check.errorf(obj.Pos(), "invalid recursive type %s", obj.Name())
+       } else {
+               check.errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name())
+       }
+       for range cycle {
+               check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+               i++
+               if i >= len(cycle) {
+                       i = 0
+               }
+               obj = cycle[i]
+       }
+       check.errorf(obj.Pos(), "\t%s", obj.Name())
+}
+
+// TODO(gri) This functionality should probably be with the Pos implementation.
+func cmpPos(p, q syntax.Pos) int {
+       // TODO(gri) is RelFilename correct here?
+       pname := p.RelFilename()
+       qname := q.RelFilename()
+       switch {
+       case pname < qname:
+               return -1
+       case pname > qname:
+               return +1
+       }
+
+       pline := p.Line()
+       qline := q.Line()
+       switch {
+       case pline < qline:
+               return -1
+       case pline > qline:
+               return +1
+       }
+
+       pcol := p.Col()
+       qcol := q.Col()
+       switch {
+       case pcol < qcol:
+               return -1
+       case pcol > qcol:
+               return +1
+       }
+
+       return 0
+}
+
+// firstInSrc reports the index of the object with the "smallest"
+// source position in path. path must not be empty.
+func firstInSrc(path []Object) int {
+       fst, pos := 0, path[0].Pos()
+       for i, t := range path[1:] {
+               if cmpPos(t.Pos(), pos) < 0 {
+                       fst, pos = i+1, t.Pos()
+               }
+       }
+       return fst
+}
+
+func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr, inherited bool) {
+       assert(obj.typ == nil)
+
+       // use the correct value of iota and errpos
+       defer func(iota constant.Value, errpos syntax.Pos) {
+               check.iota = iota
+               check.errpos = errpos
+       }(check.iota, check.errpos)
+       check.iota = obj.val
+       check.errpos = nopos
+
+       // provide valid constant value under all circumstances
+       obj.val = constant.MakeUnknown()
+
+       // determine type, if any
+       if typ != nil {
+               t := check.typ(typ)
+               if !isConstType(t) {
+                       // don't report an error if the type is an invalid C (defined) type
+                       // (issue #22090)
+                       if t.Under() != Typ[Invalid] {
+                               check.errorf(typ, "invalid constant type %s", t)
+                       }
+                       obj.typ = Typ[Invalid]
+                       return
+               }
+               obj.typ = t
+       }
+
+       // check initialization
+       var x operand
+       if init != nil {
+               if inherited {
+                       // The initialization expression is inherited from a previous
+                       // constant declaration, and (error) positions refer to that
+                       // expression and not the current constant declaration. Use
+                       // the constant identifier position for any errors during
+                       // init expression evaluation since that is all we have
+                       // (see issues #42991, #42992).
+                       check.errpos = obj.pos
+               }
+               check.expr(&x, init)
+       }
+       check.initConst(obj, &x)
+}
+
+func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) {
+       assert(obj.typ == nil)
+
+       // If we have undefined variable types due to errors,
+       // mark variables as used to avoid follow-on errors.
+       // Matches compiler behavior.
+       defer func() {
+               if obj.typ == Typ[Invalid] {
+                       obj.used = true
+               }
+               for _, lhs := range lhs {
+                       if lhs.typ == Typ[Invalid] {
+                               lhs.used = true
+                       }
+               }
+       }()
+
+       // determine type, if any
+       if typ != nil {
+               obj.typ = check.varType(typ)
+               // We cannot spread the type to all lhs variables if there
+               // are more than one since that would mark them as checked
+               // (see Checker.objDecl) and the assignment of init exprs,
+               // if any, would not be checked.
+               //
+               // TODO(gri) If we have no init expr, we should distribute
+               // a given type otherwise we need to re-evalate the type
+               // expr for each lhs variable, leading to duplicate work.
+       }
+
+       // check initialization
+       if init == nil {
+               if typ == nil {
+                       // error reported before by arityMatch
+                       obj.typ = Typ[Invalid]
+               }
+               return
+       }
+
+       if lhs == nil || len(lhs) == 1 {
+               assert(lhs == nil || lhs[0] == obj)
+               var x operand
+               check.expr(&x, init)
+               check.initVar(obj, &x, "variable declaration")
+               return
+       }
+
+       if debug {
+               // obj must be one of lhs
+               found := false
+               for _, lhs := range lhs {
+                       if obj == lhs {
+                               found = true
+                               break
+                       }
+               }
+               if !found {
+                       panic("inconsistent lhs")
+               }
+       }
+
+       // We have multiple variables on the lhs and one init expr.
+       // Make sure all variables have been given the same type if
+       // one was specified, otherwise they assume the type of the
+       // init expression values (was issue #15755).
+       if typ != nil {
+               for _, lhs := range lhs {
+                       lhs.typ = obj.typ
+               }
+       }
+
+       check.initVars(lhs, []syntax.Expr{init}, nopos)
+}
+
+// Under returns the expanded underlying type of n0; possibly by following
+// forward chains of named types. If an underlying type is found, resolve
+// the chain by setting the underlying type for each defined type in the
+// chain before returning it. If no underlying type is found or a cycle
+// is detected, the result is Typ[Invalid]. If a cycle is detected and
+// n0.check != nil, the cycle is reported.
+func (n0 *Named) Under() Type {
+       u := n0.underlying
+       if u == nil {
+               return Typ[Invalid]
+       }
+
+       // If the underlying type of a defined type is not a defined
+       // type, then that is the desired underlying type.
+       n := u.Named()
+       if n == nil {
+               return u // common case
+       }
+
+       // Otherwise, follow the forward chain.
+       seen := map[*Named]int{n0: 0}
+       path := []Object{n0.obj}
+       for {
+               u = n.underlying
+               if u == nil {
+                       u = Typ[Invalid]
+                       break
+               }
+               n1 := u.Named()
+               if n1 == nil {
+                       break // end of chain
+               }
+
+               seen[n] = len(seen)
+               path = append(path, n.obj)
+               n = n1
+
+               if i, ok := seen[n]; ok {
+                       // cycle
+                       if n0.check != nil {
+                               n0.check.cycleError(path[i:])
+                       }
+                       u = Typ[Invalid]
+                       break
+               }
+       }
+
+       for n := range seen {
+               // We should never have to update the underlying type of an imported type;
+               // those underlying types should have been resolved during the import.
+               // Also, doing so would lead to a race condition (was issue #31749).
+               // Do this check always, not just in debug more (it's cheap).
+               if n0.check != nil && n.obj.pkg != n0.check.pkg {
+                       panic("internal error: imported type with unresolved underlying type")
+               }
+               n.underlying = u
+       }
+
+       return u
+}
+
+func (n *Named) setUnderlying(typ Type) {
+       if n != nil {
+               n.underlying = typ
+       }
+}
+
+func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named) {
+       assert(obj.typ == nil)
+
+       check.later(func() {
+               check.validType(obj.typ, nil)
+       })
+
+       alias := tdecl.Alias
+       if alias && tdecl.TParamList != nil {
+               // The parser will ensure this but we may still get an invalid AST.
+               // Complain and continue as regular type definition.
+               check.errorf(tdecl, "generic type cannot be alias")
+               alias = false
+       }
+
+       if alias {
+               // type alias declaration
+
+               obj.typ = Typ[Invalid]
+               obj.typ = check.anyType(tdecl.Type)
+
+       } else {
+               // defined type declaration
+
+               named := &Named{check: check, obj: obj}
+               def.setUnderlying(named)
+               obj.typ = named // make sure recursive type declarations terminate
+
+               if tdecl.TParamList != nil {
+                       check.openScope(tdecl, "type parameters")
+                       defer check.closeScope()
+                       named.tparams = check.collectTypeParams(tdecl.TParamList)
+               }
+
+               // determine underlying type of named
+               named.orig = check.definedType(tdecl.Type, named)
+
+               // The underlying type of named may be itself a named type that is
+               // incomplete:
+               //
+               //      type (
+               //              A B
+               //              B *C
+               //              C A
+               //      )
+               //
+               // The type of C is the (named) type of A which is incomplete,
+               // and which has as its underlying type the named type B.
+               // Determine the (final, unnamed) underlying type by resolving
+               // any forward chain.
+               // TODO(gri) Investigate if we can just use named.origin here
+               //           and rely on lazy computation of the underlying type.
+               named.underlying = named.Under()
+       }
+
+}
+
+func (check *Checker) collectTypeParams(list []*syntax.Field) (tparams []*TypeName) {
+       // Type parameter lists should not be empty. The parser will
+       // complain but we still may get an incorrect AST: ignore it.
+       if len(list) == 0 {
+               return
+       }
+
+       // Declare type parameters up-front, with empty interface as type bound.
+       // The scope of type parameters starts at the beginning of the type parameter
+       // list (so we can have mutually recursive parameterized interfaces).
+       for _, f := range list {
+               tparams = check.declareTypeParam(tparams, f.Name)
+       }
+
+       var bound Type
+       for i, j := 0, 0; i < len(list); i = j {
+               f := list[i]
+
+               // determine the range of type parameters list[i:j] with identical type bound
+               // (declared as in (type a, b, c B))
+               j = i + 1
+               for j < len(list) && list[j].Type == f.Type {
+                       j++
+               }
+
+               // this should never be the case, but be careful
+               if f.Type == nil {
+                       continue
+               }
+
+               // The predeclared identifier "any" is visible only as a constraint
+               // in a type parameter list. Look for it before general constraint
+               // resolution.
+               if tident, _ := f.Type.(*syntax.Name); tident != nil && tident.Value == "any" && check.lookup("any") == nil {
+                       bound = universeAny
+               } else {
+                       bound = check.typ(f.Type)
+               }
+
+               // type bound must be an interface
+               // TODO(gri) We should delay the interface check because
+               //           we may not have a complete interface yet:
+               //           type C(type T C) interface {}
+               //           (issue #39724).
+               if _, ok := bound.Under().(*Interface); ok {
+                       // set the type bounds
+                       for i < j {
+                               tparams[i].typ.(*TypeParam).bound = bound
+                               i++
+                       }
+               } else if bound != Typ[Invalid] {
+                       check.errorf(f.Type, "%s is not an interface", bound)
+               }
+       }
+
+       return
+}
+
+func (check *Checker) declareTypeParam(tparams []*TypeName, name *syntax.Name) []*TypeName {
+       tpar := NewTypeName(name.Pos(), check.pkg, name.Value, nil)
+       check.NewTypeParam(tpar, len(tparams), &emptyInterface) // assigns type to tpar as a side-effect
+       check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position
+       tparams = append(tparams, tpar)
+
+       if check.conf.Trace {
+               check.trace(name.Pos(), "type param = %v", tparams[len(tparams)-1])
+       }
+
+       return tparams
+}
+
+func (check *Checker) collectMethods(obj *TypeName) {
+       // get associated methods
+       // (Checker.collectObjects only collects methods with non-blank names;
+       // Checker.resolveBaseTypeName ensures that obj is not an alias name
+       // if it has attached methods.)
+       methods := check.methods[obj]
+       if methods == nil {
+               return
+       }
+       delete(check.methods, obj)
+       assert(!check.objMap[obj].tdecl.Alias) // don't use TypeName.IsAlias (requires fully set up object)
+
+       // use an objset to check for name conflicts
+       var mset objset
+
+       // spec: "If the base type is a struct type, the non-blank method
+       // and field names must be distinct."
+       base := obj.typ.Named() // shouldn't fail but be conservative
+       if base != nil {
+               if t, _ := base.underlying.(*Struct); t != nil {
+                       for _, fld := range t.fields {
+                               if fld.name != "_" {
+                                       assert(mset.insert(fld) == nil)
+                               }
+                       }
+               }
+
+               // Checker.Files may be called multiple times; additional package files
+               // may add methods to already type-checked types. Add pre-existing methods
+               // so that we can detect redeclarations.
+               for _, m := range base.methods {
+                       assert(m.name != "_")
+                       assert(mset.insert(m) == nil)
+               }
+       }
+
+       // add valid methods
+       for _, m := range methods {
+               // spec: "For a base type, the non-blank names of methods bound
+               // to it must be unique."
+               assert(m.name != "_")
+               if alt := mset.insert(m); alt != nil {
+                       switch alt.(type) {
+                       case *Var:
+                               check.errorf(m.pos, "field and method with the same name %s", m.name)
+                       case *Func:
+                               if check.conf.CompilerErrorMessages {
+                                       check.errorf(m.pos, "%s.%s redeclared in this block", obj.Name(), m.name)
+                               } else {
+                                       check.errorf(m.pos, "method %s already declared for %s", m.name, obj)
+                               }
+                       default:
+                               unreachable()
+                       }
+                       check.reportAltDecl(alt)
+                       continue
+               }
+
+               if base != nil {
+                       base.methods = append(base.methods, m)
+               }
+       }
+}
+
+func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
+       assert(obj.typ == nil)
+
+       // func declarations cannot use iota
+       assert(check.iota == nil)
+
+       sig := new(Signature)
+       obj.typ = sig // guard against cycles
+
+       // Avoid cycle error when referring to method while type-checking the signature.
+       // This avoids a nuisance in the best case (non-parameterized receiver type) and
+       // since the method is not a type, we get an error. If we have a parameterized
+       // receiver type, instantiating the receiver type leads to the instantiation of
+       // its methods, and we don't want a cycle error in that case.
+       // TODO(gri) review if this is correct and/or whether we still need this?
+       saved := obj.color_
+       obj.color_ = black
+       fdecl := decl.fdecl
+       check.funcType(sig, fdecl.Recv, fdecl.TParamList, fdecl.Type)
+       obj.color_ = saved
+
+       // function body must be type-checked after global declarations
+       // (functions implemented elsewhere have no body)
+       if !check.conf.IgnoreFuncBodies && fdecl.Body != nil {
+               check.later(func() {
+                       check.funcBody(decl, obj.name, sig, fdecl.Body, nil)
+               })
+       }
+}
+
+func (check *Checker) declStmt(list []syntax.Decl) {
+       pkg := check.pkg
+
+       first := -1                // index of first ConstDecl in the current group, or -1
+       var last *syntax.ConstDecl // last ConstDecl with init expressions, or nil
+       for index, decl := range list {
+               if _, ok := decl.(*syntax.ConstDecl); !ok {
+                       first = -1 // we're not in a constant declaration
+               }
+
+               switch s := decl.(type) {
+               case *syntax.ConstDecl:
+                       top := len(check.delayed)
+
+                       // iota is the index of the current constDecl within the group
+                       if first < 0 || list[index-1].(*syntax.ConstDecl).Group != s.Group {
+                               first = index
+                               last = nil
+                       }
+                       iota := constant.MakeInt64(int64(index - first))
+
+                       // determine which initialization expressions to use
+                       inherited := true
+                       switch {
+                       case s.Type != nil || s.Values != nil:
+                               last = s
+                               inherited = false
+                       case last == nil:
+                               last = new(syntax.ConstDecl) // make sure last exists
+                               inherited = false
+                       }
+
+                       // declare all constants
+                       lhs := make([]*Const, len(s.NameList))
+                       values := unpackExpr(last.Values)
+                       for i, name := range s.NameList {
+                               obj := NewConst(name.Pos(), pkg, name.Value, nil, iota)
+                               lhs[i] = obj
+
+                               var init syntax.Expr
+                               if i < len(values) {
+                                       init = values[i]
+                               }
+
+                               check.constDecl(obj, last.Type, init, inherited)
+                       }
+
+                       // Constants must always have init values.
+                       check.arity(s.Pos(), s.NameList, values, true, inherited)
+
+                       // process function literals in init expressions before scope changes
+                       check.processDelayed(top)
+
+                       // spec: "The scope of a constant or variable identifier declared
+                       // inside a function begins at the end of the ConstSpec or VarSpec
+                       // (ShortVarDecl for short variable declarations) and ends at the
+                       // end of the innermost containing block."
+                       scopePos := endPos(s)
+                       for i, name := range s.NameList {
+                               check.declare(check.scope, name, lhs[i], scopePos)
+                       }
+
+               case *syntax.VarDecl:
+                       top := len(check.delayed)
+
+                       lhs0 := make([]*Var, len(s.NameList))
+                       for i, name := range s.NameList {
+                               lhs0[i] = NewVar(name.Pos(), pkg, name.Value, nil)
+                       }
+
+                       // initialize all variables
+                       values := unpackExpr(s.Values)
+                       for i, obj := range lhs0 {
+                               var lhs []*Var
+                               var init syntax.Expr
+                               switch len(values) {
+                               case len(s.NameList):
+                                       // lhs and rhs match
+                                       init = values[i]
+                               case 1:
+                                       // rhs is expected to be a multi-valued expression
+                                       lhs = lhs0
+                                       init = values[0]
+                               default:
+                                       if i < len(values) {
+                                               init = values[i]
+                                       }
+                               }
+                               check.varDecl(obj, lhs, s.Type, init)
+                               if len(values) == 1 {
+                                       // If we have a single lhs variable we are done either way.
+                                       // If we have a single rhs expression, it must be a multi-
+                                       // valued expression, in which case handling the first lhs
+                                       // variable will cause all lhs variables to have a type
+                                       // assigned, and we are done as well.
+                                       if debug {
+                                               for _, obj := range lhs0 {
+                                                       assert(obj.typ != nil)
+                                               }
+                                       }
+                                       break
+                               }
+                       }
+
+                       // If we have no type, we must have values.
+                       if s.Type == nil || values != nil {
+                               check.arity(s.Pos(), s.NameList, values, false, false)
+                       }
+
+                       // process function literals in init expressions before scope changes
+                       check.processDelayed(top)
+
+                       // declare all variables
+                       // (only at this point are the variable scopes (parents) set)
+                       scopePos := endPos(s) // see constant declarations
+                       for i, name := range s.NameList {
+                               // see constant declarations
+                               check.declare(check.scope, name, lhs0[i], scopePos)
+                       }
+
+               case *syntax.TypeDecl:
+                       obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil)
+                       // spec: "The scope of a type identifier declared inside a function
+                       // begins at the identifier in the TypeSpec and ends at the end of
+                       // the innermost containing block."
+                       scopePos := s.Name.Pos()
+                       check.declare(check.scope, s.Name, obj, scopePos)
+                       // mark and unmark type before calling typeDecl; its type is still nil (see Checker.objDecl)
+                       obj.setColor(grey + color(check.push(obj)))
+                       check.typeDecl(obj, s, nil)
+                       check.pop().setColor(black)
+
+               default:
+                       check.invalidASTf(s, "unknown syntax.Decl node %T", s)
+               }
+       }
+}
diff --git a/src/cmd/compile/internal/types2/errors.go b/src/cmd/compile/internal/types2/errors.go
new file mode 100644 (file)
index 0000000..941e7c6
--- /dev/null
@@ -0,0 +1,172 @@
+// UNREVIEWED
+// Copyright 2012 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.
+
+// This file implements various error reporters.
+
+package types2
+
+import (
+       "bytes"
+       "cmd/compile/internal/syntax"
+       "fmt"
+       "strconv"
+       "strings"
+)
+
+func unimplemented() {
+       panic("unimplemented")
+}
+
+func assert(p bool) {
+       if !p {
+               panic("assertion failed")
+       }
+}
+
+func unreachable() {
+       panic("unreachable")
+}
+
+func (check *Checker) qualifier(pkg *Package) string {
+       // Qualify the package unless it's the package being type-checked.
+       if pkg != check.pkg {
+               // If the same package name was used by multiple packages, display the full path.
+               if check.pkgCnt[pkg.name] > 1 {
+                       return strconv.Quote(pkg.path)
+               }
+               return pkg.name
+       }
+       return ""
+}
+
+func (check *Checker) sprintf(format string, args ...interface{}) string {
+       for i, arg := range args {
+               switch a := arg.(type) {
+               case nil:
+                       arg = "<nil>"
+               case operand:
+                       panic("internal error: should always pass *operand")
+               case *operand:
+                       arg = operandString(a, check.qualifier)
+               case syntax.Pos:
+                       arg = a.String()
+               case syntax.Expr:
+                       arg = ExprString(a)
+               case Object:
+                       arg = ObjectString(a, check.qualifier)
+               case Type:
+                       arg = TypeString(a, check.qualifier)
+               }
+               args[i] = arg
+       }
+       return fmt.Sprintf(format, args...)
+}
+
+func (check *Checker) trace(pos syntax.Pos, format string, args ...interface{}) {
+       fmt.Printf("%s:\t%s%s\n",
+               pos,
+               strings.Repeat(".  ", check.indent),
+               check.sprintf(format, args...),
+       )
+}
+
+// dump is only needed for debugging
+func (check *Checker) dump(format string, args ...interface{}) {
+       fmt.Println(check.sprintf(format, args...))
+}
+
+func (check *Checker) err(pos syntax.Pos, msg string, soft bool) {
+       // Cheap trick: Don't report errors with messages containing
+       // "invalid operand" or "invalid type" as those tend to be
+       // follow-on errors which don't add useful information. Only
+       // exclude them if these strings are not at the beginning,
+       // and only if we have at least one error already reported.
+       if check.firstErr != nil && (strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0) {
+               return
+       }
+
+       // If we are encountering an error while evaluating an inherited
+       // constant initialization expression, pos is the position of in
+       // the original expression, and not of the currently declared
+       // constant identifier. Use the provided errpos instead.
+       // TODO(gri) We may also want to augment the error message and
+       // refer to the position (pos) in the original expression.
+       if check.errpos.IsKnown() {
+               assert(check.iota != nil)
+               pos = check.errpos
+       }
+
+       err := Error{pos, stripAnnotations(msg), msg, soft}
+       if check.firstErr == nil {
+               check.firstErr = err
+       }
+
+       if check.conf.Trace {
+               check.trace(pos, "ERROR: %s", msg)
+       }
+
+       f := check.conf.Error
+       if f == nil {
+               panic(bailout{}) // report only first error
+       }
+       f(err)
+}
+
+type poser interface {
+       Pos() syntax.Pos
+}
+
+func (check *Checker) error(at poser, msg string) {
+       check.err(posFor(at), msg, false)
+}
+
+func (check *Checker) errorf(at poser, format string, args ...interface{}) {
+       check.err(posFor(at), check.sprintf(format, args...), false)
+}
+
+func (check *Checker) softErrorf(at poser, format string, args ...interface{}) {
+       check.err(posFor(at), check.sprintf(format, args...), true)
+}
+
+func (check *Checker) invalidASTf(at poser, format string, args ...interface{}) {
+       check.errorf(at, "invalid AST: "+format, args...)
+}
+
+func (check *Checker) invalidArgf(at poser, format string, args ...interface{}) {
+       check.errorf(at, "invalid argument: "+format, args...)
+}
+
+func (check *Checker) invalidOpf(at poser, format string, args ...interface{}) {
+       check.errorf(at, "invalid operation: "+format, args...)
+}
+
+// posFor reports the left (= start) position of at.
+func posFor(at poser) syntax.Pos {
+       switch x := at.(type) {
+       case *operand:
+               if x.expr != nil {
+                       return startPos(x.expr)
+               }
+       case syntax.Node:
+               return startPos(x)
+       }
+       return at.Pos()
+}
+
+// stripAnnotations removes internal (type) annotations from s.
+func stripAnnotations(s string) string {
+       // Would like to use strings.Builder but it's not available in Go 1.4.
+       var b bytes.Buffer
+       for _, r := range s {
+               // strip #'s and subscript digits
+               if r != instanceMarker && !('₀' <= r && r < '₀'+10) { // '₀' == U+2080
+                       b.WriteRune(r)
+               }
+       }
+       if b.Len() < len(s) {
+               return b.String()
+       }
+       return s
+}
diff --git a/src/cmd/compile/internal/types2/errors_test.go b/src/cmd/compile/internal/types2/errors_test.go
new file mode 100644 (file)
index 0000000..51ae5fd
--- /dev/null
@@ -0,0 +1,26 @@
+// UNREVIEWED
+// Copyright 2020 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 "testing"
+
+func TestStripAnnotations(t *testing.T) {
+       for _, test := range []struct {
+               in, want string
+       }{
+               {"", ""},
+               {"   ", "   "},
+               {"foo", "foo"},
+               {"foo₀", "foo"},
+               {"foo(T₀)", "foo(T)"},
+               {"#foo(T₀)", "foo(T)"},
+       } {
+               got := stripAnnotations(test.in)
+               if got != test.want {
+                       t.Errorf("%q: got %q; want %q", test.in, got, test.want)
+               }
+       }
+}
diff --git a/src/cmd/compile/internal/types2/example_test.go b/src/cmd/compile/internal/types2/example_test.go
new file mode 100644 (file)
index 0000000..dcdeaca
--- /dev/null
@@ -0,0 +1,324 @@
+// UNREVIEWED
+// Copyright 2015 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.
+
+// Only run where builders (build.golang.org) have
+// access to compiled packages for import.
+//
+// +build !arm,!arm64
+
+package types2_test
+
+// This file shows examples of basic usage of the go/types API.
+//
+// To locate a Go package, use (*go/build.Context).Import.
+// To load, parse, and type-check a complete Go program
+// from source, use golang.org/x/tools/go/loader.
+
+import (
+       "bytes"
+       "cmd/compile/internal/syntax"
+       "cmd/compile/internal/types2"
+       "fmt"
+       "log"
+       "regexp"
+       "sort"
+       "strings"
+)
+
+// ExampleScope prints the tree of Scopes of a package created from a
+// set of parsed files.
+func ExampleScope() {
+       // Parse the source files for a package.
+       var files []*syntax.File
+       for _, file := range []struct{ name, input string }{
+               {"main.go", `
+package main
+import "fmt"
+func main() {
+       freezing := FToC(-18)
+       fmt.Println(freezing, Boiling) }
+`},
+               {"celsius.go", `
+package main
+import "fmt"
+type Celsius float64
+func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
+func FToC(f float64) Celsius { return Celsius(f - 32 / 9 * 5) }
+const Boiling Celsius = 100
+func Unused() { {}; {{ var x int; _ = x }} } // make sure empty block scopes get printed
+`},
+       } {
+               f, err := parseSrc(file.name, file.input)
+               if err != nil {
+                       log.Fatal(err)
+               }
+               files = append(files, f)
+       }
+
+       // Type-check a package consisting of these files.
+       // Type information for the imported "fmt" package
+       // comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a.
+       conf := types2.Config{Importer: defaultImporter()}
+       pkg, err := conf.Check("temperature", files, nil)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       // Print the tree of scopes.
+       // For determinism, we redact addresses.
+       var buf bytes.Buffer
+       pkg.Scope().WriteTo(&buf, 0, true)
+       rx := regexp.MustCompile(` 0x[a-fA-F0-9]*`)
+       fmt.Println(rx.ReplaceAllString(buf.String(), ""))
+
+       // Output:
+       // package "temperature" scope {
+       // .  const temperature.Boiling temperature.Celsius
+       // .  type temperature.Celsius float64
+       // .  func temperature.FToC(f float64) temperature.Celsius
+       // .  func temperature.Unused()
+       // .  func temperature.main()
+       // .  main.go scope {
+       // .  .  package fmt
+       // .  .  function scope {
+       // .  .  .  var freezing temperature.Celsius
+       // .  .  }
+       // .  }
+       // .  celsius.go scope {
+       // .  .  package fmt
+       // .  .  function scope {
+       // .  .  .  var c temperature.Celsius
+       // .  .  }
+       // .  .  function scope {
+       // .  .  .  var f float64
+       // .  .  }
+       // .  .  function scope {
+       // .  .  .  block scope {
+       // .  .  .  }
+       // .  .  .  block scope {
+       // .  .  .  .  block scope {
+       // .  .  .  .  .  var x int
+       // .  .  .  .  }
+       // .  .  .  }
+       // .  .  }
+       // .  }
+       // }
+}
+
+// ExampleMethodSet prints the method sets of various types.
+func ExampleMethodSet() {
+       // Parse a single source file.
+       const input = `
+package temperature
+import "fmt"
+type Celsius float64
+func (c Celsius) String() string  { return fmt.Sprintf("%g°C", c) }
+func (c *Celsius) SetF(f float64) { *c = Celsius(f - 32 / 9 * 5) }
+
+type S struct { I; m int }
+type I interface { m() byte }
+`
+       f, err := parseSrc("celsius.go", input)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       // Type-check a package consisting of this file.
+       // Type information for the imported packages
+       // comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a.
+       conf := types2.Config{Importer: defaultImporter()}
+       pkg, err := conf.Check("temperature", []*syntax.File{f}, nil)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       // Print the method sets of Celsius and *Celsius.
+       celsius := pkg.Scope().Lookup("Celsius").Type()
+       for _, t := range []types2.Type{celsius, types2.NewPointer(celsius)} {
+               fmt.Printf("Method set of %s:\n", t)
+               mset := types2.NewMethodSet(t)
+               for i := 0; i < mset.Len(); i++ {
+                       fmt.Println(mset.At(i))
+               }
+               fmt.Println()
+       }
+
+       // Print the method set of S.
+       styp := pkg.Scope().Lookup("S").Type()
+       fmt.Printf("Method set of %s:\n", styp)
+       fmt.Println(types2.NewMethodSet(styp))
+
+       // Output:
+       // Method set of temperature.Celsius:
+       // method (temperature.Celsius) String() string
+       //
+       // Method set of *temperature.Celsius:
+       // method (*temperature.Celsius) SetF(f float64)
+       // method (*temperature.Celsius) String() string
+       //
+       // Method set of temperature.S:
+       // MethodSet {}
+}
+
+// ExampleInfo prints various facts recorded by the type checker in a
+// types2.Info struct: definitions of and references to each named object,
+// and the type, value, and mode of every expression in the package.
+func ExampleInfo() {
+       // Parse a single source file.
+       const input = `
+package fib
+
+type S string
+
+var a, b, c = len(b), S(c), "hello"
+
+func fib(x int) int {
+       if x < 2 {
+               return x
+       }
+       return fib(x-1) - fib(x-2)
+}`
+       f, err := parseSrc("fib.go", input)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       // Type-check the package.
+       // We create an empty map for each kind of input
+       // we're interested in, and Check populates them.
+       info := types2.Info{
+               Types: make(map[syntax.Expr]types2.TypeAndValue),
+               Defs:  make(map[*syntax.Name]types2.Object),
+               Uses:  make(map[*syntax.Name]types2.Object),
+       }
+       var conf types2.Config
+       pkg, err := conf.Check("fib", []*syntax.File{f}, &info)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       // Print package-level variables in initialization order.
+       fmt.Printf("InitOrder: %v\n\n", info.InitOrder)
+
+       // For each named object, print the line and
+       // column of its definition and each of its uses.
+       fmt.Println("Defs and Uses of each named object:")
+       usesByObj := make(map[types2.Object][]string)
+       for id, obj := range info.Uses {
+               posn := id.Pos()
+               lineCol := fmt.Sprintf("%d:%d", posn.Line(), posn.Col())
+               usesByObj[obj] = append(usesByObj[obj], lineCol)
+       }
+       var items []string
+       for obj, uses := range usesByObj {
+               sort.Strings(uses)
+               item := fmt.Sprintf("%s:\n  defined at %s\n  used at %s",
+                       types2.ObjectString(obj, types2.RelativeTo(pkg)),
+                       obj.Pos(),
+                       strings.Join(uses, ", "))
+               items = append(items, item)
+       }
+       sort.Strings(items) // sort by line:col, in effect
+       fmt.Println(strings.Join(items, "\n"))
+       fmt.Println()
+
+       // TODO(gri) Enable once positions are updated/verified
+       // fmt.Println("Types and Values of each expression:")
+       // items = nil
+       // for expr, tv := range info.Types {
+       //      var buf bytes.Buffer
+       //      posn := expr.Pos()
+       //      tvstr := tv.Type.String()
+       //      if tv.Value != nil {
+       //              tvstr += " = " + tv.Value.String()
+       //      }
+       //      // line:col | expr | mode : type = value
+       //      fmt.Fprintf(&buf, "%2d:%2d | %-19s | %-7s : %s",
+       //              posn.Line(), posn.Col(), types2.ExprString(expr),
+       //              mode(tv), tvstr)
+       //      items = append(items, buf.String())
+       // }
+       // sort.Strings(items)
+       // fmt.Println(strings.Join(items, "\n"))
+
+       // Output:
+       // InitOrder: [c = "hello" b = S(c) a = len(b)]
+       //
+       // Defs and Uses of each named object:
+       // builtin len:
+       //   defined at <unknown position>
+       //   used at 6:15
+       // func fib(x int) int:
+       //   defined at fib.go:8:6
+       //   used at 12:20, 12:9
+       // type S string:
+       //   defined at fib.go:4:6
+       //   used at 6:23
+       // type int:
+       //   defined at <unknown position>
+       //   used at 8:12, 8:17
+       // type string:
+       //   defined at <unknown position>
+       //   used at 4:8
+       // var b S:
+       //   defined at fib.go:6:8
+       //   used at 6:19
+       // var c string:
+       //   defined at fib.go:6:11
+       //   used at 6:25
+       // var x int:
+       //   defined at fib.go:8:10
+       //   used at 10:10, 12:13, 12:24, 9:5
+
+       // TODO(gri) Enable once positions are updated/verified
+       // Types and Values of each expression:
+       //  4: 8 | string              | type    : string
+       //  6:15 | len                 | builtin : func(string) int
+       //  6:15 | len(b)              | value   : int
+       //  6:19 | b                   | var     : fib.S
+       //  6:23 | S                   | type    : fib.S
+       //  6:23 | S(c)                | value   : fib.S
+       //  6:25 | c                   | var     : string
+       //  6:29 | "hello"             | value   : string = "hello"
+       //  8:12 | int                 | type    : int
+       //  8:17 | int                 | type    : int
+       //  9: 5 | x                   | var     : int
+       //  9: 5 | x < 2               | value   : untyped bool
+       //  9: 9 | 2                   | value   : int = 2
+       // 10:10 | x                   | var     : int
+       // 12: 9 | fib                 | value   : func(x int) int
+       // 12: 9 | fib(x - 1)          | value   : int
+       // 12: 9 | fib(x - 1) - fib(x - 2) | value   : int
+       // 12:13 | x                   | var     : int
+       // 12:13 | x - 1               | value   : int
+       // 12:15 | 1                   | value   : int = 1
+       // 12:20 | fib                 | value   : func(x int) int
+       // 12:20 | fib(x - 2)          | value   : int
+       // 12:24 | x                   | var     : int
+       // 12:24 | x - 2               | value   : int
+       // 12:26 | 2                   | value   : int = 2
+}
+
+func mode(tv types2.TypeAndValue) string {
+       switch {
+       case tv.IsVoid():
+               return "void"
+       case tv.IsType():
+               return "type"
+       case tv.IsBuiltin():
+               return "builtin"
+       case tv.IsNil():
+               return "nil"
+       case tv.Assignable():
+               if tv.Addressable() {
+                       return "var"
+               }
+               return "mapindex"
+       case tv.IsValue():
+               return "value"
+       default:
+               return "unknown"
+       }
+}
diff --git a/src/cmd/compile/internal/types2/examples/functions.go2 b/src/cmd/compile/internal/types2/examples/functions.go2
new file mode 100644 (file)
index 0000000..ab4c192
--- /dev/null
@@ -0,0 +1,216 @@
+// UNREVIEWED
+// Copyright 2019 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.
+
+// This file shows some examples of type-parameterized functions.
+
+package p
+
+// Reverse is a generic function that takes a []T argument and
+// reverses that slice in place.
+func Reverse[T any](list []T) {
+       i := 0
+       j := len(list)-1
+       for i < j {
+               list[i], list[j] = list[j], list[i]
+               i++
+               j--
+       }
+}
+
+func _() {
+       // Reverse can be called with an explicit type argument.
+       Reverse[int](nil)
+       Reverse[string]([]string{"foo", "bar"})
+       Reverse[struct{x, y int}]([]struct{x, y int}{{1, 2}, {2, 3}, {3, 4}})
+
+       // Since the type parameter is used for an incoming argument,
+       // it can be inferred from the provided argument's type.
+       Reverse([]string{"foo", "bar"})
+       Reverse([]struct{x, y int}{{1, 2}, {2, 3}, {3, 4}})
+
+       // But the incoming argument must have a type, even if it's a
+       // default type. An untyped nil won't work.
+       // Reverse(nil) // this won't type-check
+
+       // A typed nil will work, though.
+       Reverse([]int(nil))
+}
+
+// Certain functions, such as the built-in `new` could be written using
+// type parameters.
+func new[T any]() *T {
+       var x T
+       return &x
+}
+
+// When calling our own `new`, we need to pass the type parameter
+// explicitly since there is no (value) argument from which the
+// result type could be inferred. We don't try to infer the
+// result type from the assignment to keep things simple and
+// easy to understand.
+var _ = new[int]()
+var _ *float64 = new[float64]() // the result type is indeed *float64
+
+// A function may have multiple type parameters, of course.
+func foo[A, B, C any](a A, b []B, c *C) B {
+       // do something here
+       return b[0]
+}
+
+// As before, we can pass type parameters explicitly.
+var s = foo[int, string, float64](1, []string{"first"}, new[float64]())
+
+// Or we can use type inference.
+var _ float64 = foo(42, []float64{1.0}, &s)
+
+// Type inference works in a straight-forward manner even
+// for variadic functions.
+func variadic[A, B any](A, B, ...B) int
+
+// var _ = variadic(1) // ERROR not enough arguments
+var _ = variadic(1, 2.3)
+var _ = variadic(1, 2.3, 3.4, 4.5)
+var _ = variadic[int, float64](1, 2.3, 3.4, 4)
+
+// Type inference also works in recursive function calls where
+// the inferred type is the type parameter of the caller.
+func f1[T any](x T) {
+       f1(x)
+}
+
+func f2a[T any](x, y T) {
+       f2a(x, y)
+}
+
+func f2b[T any](x, y T) {
+       f2b(y, x)
+}
+
+func g2a[P, Q any](x P, y Q) {
+       g2a(x, y)
+}
+
+func g2b[P, Q any](x P, y Q) {
+       g2b(y, x)
+}
+
+// Here's an example of a recursive function call with variadic
+// arguments and type inference inferring the type parameter of
+// the caller (i.e., itself).
+func max[T interface{ type int }](x ...T) T {
+       var x0 T
+       if len(x) > 0 {
+               x0 = x[0]
+       }
+       if len(x) > 1 {
+               x1 := max(x[1:]...)
+               if x1 > x0 {
+                       return x1
+               }
+       }
+       return x0
+}
+
+// When inferring channel types, the channel direction is ignored
+// for the purpose of type inference. Once the type has been in-
+// fered, the usual parameter passing rules are applied.
+// Thus even if a type can be inferred successfully, the function
+// call may not be valid.
+
+func fboth[T any](chan T)
+func frecv[T any](<-chan T)
+func fsend[T any](chan<- T)
+
+func _() {
+       var both chan int
+       var recv <-chan int
+       var send chan<-int
+
+       fboth(both)
+       fboth(recv /* ERROR cannot use */ )
+       fboth(send /* ERROR cannot use */ )
+
+       frecv(both)
+       frecv(recv)
+       frecv(send /* ERROR cannot use */ )
+
+       fsend(both)
+       fsend(recv /* ERROR cannot use */)
+       fsend(send)
+}
+
+func ffboth[T any](func(chan T))
+func ffrecv[T any](func(<-chan T))
+func ffsend[T any](func(chan<- T))
+
+func _() {
+       var both func(chan int)
+       var recv func(<-chan int)
+       var send func(chan<- int)
+
+       ffboth(both)
+       ffboth(recv /* ERROR cannot use */ )
+       ffboth(send /* ERROR cannot use */ )
+
+       ffrecv(both /* ERROR cannot use */ )
+       ffrecv(recv)
+       ffrecv(send /* ERROR cannot use */ )
+
+       ffsend(both /* ERROR cannot use */ )
+       ffsend(recv /* ERROR cannot use */ )
+       ffsend(send)
+}
+
+// When inferring elements of unnamed composite parameter types,
+// if the arguments are defined types, use their underlying types.
+// Even though the matching types are not exactly structurally the
+// same (one is a type literal, the other a named type), because
+// assignment is permitted, parameter passing is permitted as well,
+// so type inference should be able to handle these cases well.
+
+func g1[T any]([]T)
+func g2[T any]([]T, T)
+func g3[T any](*T, ...T)
+
+func _() {
+       type intSlize []int
+       g1([]int{})
+       g1(intSlize{})
+       g2(nil, 0)
+
+       type myString string
+       var s1 string
+       g3(nil, "1", myString("2"), "3")
+       g3(&s1, "1", myString /* ERROR does not match */ ("2"), "3")
+       _ = s1
+
+       type myStruct struct{x int}
+       var s2 myStruct
+       g3(nil, struct{x int}{}, myStruct{})
+       g3(&s2, struct{x int}{}, myStruct{})
+       g3(nil, myStruct{}, struct{x int}{})
+       g3(&s2, myStruct{}, struct{x int}{})
+}
+
+// Here's a realistic example.
+
+func append[T any](s []T, t ...T) []T
+
+func _() {
+       var f func()
+       type Funcs []func()
+       var funcs Funcs
+       _ = append(funcs, f)
+}
+
+// Generic type declarations cannot have empty type parameter lists
+// (that would indicate a slice type). Thus, generic functions cannot
+// have empty type parameter lists, either. This is a syntax error.
+
+func h[] /* ERROR empty type parameter list */ ()
+
+func _() {
+       h[] /* ERROR operand */ ()
+}
diff --git a/src/cmd/compile/internal/types2/examples/methods.go2 b/src/cmd/compile/internal/types2/examples/methods.go2
new file mode 100644 (file)
index 0000000..52f835f
--- /dev/null
@@ -0,0 +1,97 @@
+// UNREVIEWED
+// Copyright 2019 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.
+
+// This file shows some examples of methods on type-parameterized types.
+
+package p
+
+// Parameterized types may have methods.
+type T1[A any] struct{ a A }
+
+// When declaring a method for a parameterized type, the "instantiated"
+// receiver type acts as an implicit declaration of the type parameters
+// for the receiver type. In the example below, method m1 on type T1 has
+// the receiver type T1[A] which declares the type parameter A for use
+// with this method. That is, within the method m1, A stands for the
+// actual type argument provided to an instantiated T1.
+func (t T1[A]) m1() A { return t.a }
+
+// For instance, if T1 is instantiated with the type int, the type
+// parameter A in m1 assumes that type (int) as well and we can write
+// code like this:
+var x T1[int]
+var _ int = x.m1()
+
+// Because the type parameter provided to a parameterized receiver type
+// is declared through that receiver declaration, it must be an identifier.
+// It cannot possibly be some other type because the receiver type is not
+// instantiated with concrete types, it is standing for the parameterized
+// receiver type.
+func (t T1[[ /* ERROR must be an identifier */ ]int]) m2() {}
+
+// Note that using what looks like a predeclared identifier, say int,
+// as type parameter in this situation is deceptive and considered bad
+// style. In m3 below, int is the name of the local receiver type parameter
+// and it shadows the predeclared identifier int which then cannot be used
+// anymore as expected.
+// This is no different from locally redelaring a predeclared identifier
+// and usually should be avoided. There are some notable exceptions; e.g.,
+// sometimes it makes sense to use the identifier "copy" which happens to
+// also be the name of a predeclared built-in function.
+func (t T1[int]) m3() { var _ int = 42 /* ERROR cannot convert 42 .* to int */ }
+
+// The names of the type parameters used in a parameterized receiver
+// type don't have to match the type parameter names in the the declaration
+// of the type used for the receiver. In our example, even though T1 is
+// declared with type parameter named A, methods using that receiver type
+// are free to use their own name for that type parameter. That is, the
+// name of type parameters is always local to the declaration where they
+// are introduced. In our example we can write a method m2 and use the
+// name X instead of A for the type parameter w/o any difference.
+func (t T1[X]) m4() X { return t.a }
+
+// If the receiver type is parameterized, type parameters must always be
+// provided: this simply follows from the general rule that a parameterized
+// type must be instantiated before it can be used. A method receiver
+// declaration using a parameterized receiver type is no exception. It is
+// simply that such receiver type expressions perform two tasks simultaneously:
+// they declare the (local) type parameters and then use them to instantiate
+// the receiver type. Forgetting to provide a type parameter leads to an error.
+func (t T1 /* ERROR generic type .* without instantiation */ ) m5() {}
+
+// However, sometimes we don't need the type parameter, and thus it is
+// inconvenient to have to choose a name. Since the receiver type expression
+// serves as a declaration for its type parameters, we are free to choose the
+// blank identifier:
+func (t T1[_]) m6() {}
+
+// Naturally, these rules apply to any number of type parameters on the receiver
+// type. Here are some more complex examples.
+type T2[A, B, C any] struct {
+        a A
+        b B
+        c C
+}
+
+// Naming of the type parameters is local and has no semantic impact:
+func (t T2[A, B, C]) m1() (A, B, C) { return t.a, t.b, t.c }
+func (t T2[C, B, A]) m2() (C, B, A) { return t.a, t.b, t.c }
+func (t T2[X, Y, Z]) m3() (X, Y, Z) { return t.a, t.b, t.c }
+
+// Type parameters may be left blank if they are not needed:
+func (t T2[A, _, C]) m4() (A, C) { return t.a, t.c }
+func (t T2[_, _, X]) m5() X { return t.c }
+func (t T2[_, _, _]) m6() {}
+
+// As usual, blank names may be used for any object which we don't care about
+// using later. For instance, we may write an unnamed method with a receiver
+// that cannot be accessed:
+func (_ T2[_, _, _]) _() int { return 42 }
+
+// Because a receiver parameter list is simply a parameter list, we can
+// leave the receiver argument away for receiver types.
+type T0 struct{}
+func (T0) _() {}
+func (T1[A]) _() {}
diff --git a/src/cmd/compile/internal/types2/examples/types.go2 b/src/cmd/compile/internal/types2/examples/types.go2
new file mode 100644 (file)
index 0000000..be8d44e
--- /dev/null
@@ -0,0 +1,261 @@
+// UNREVIEWED
+// Copyright 2019 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.
+
+// This file shows some examples of generic types.
+
+package p
+
+// List is just what it says - a slice of E elements.
+type List[E any] []E
+
+// A generic (parameterized) type must always be instantiated
+// before it can be used to designate the type of a variable
+// (including a struct field, or function parameter); though
+// for the latter cases, the provided type may be another type
+// parameter. So:
+var _ List[byte] = []byte{}
+
+// A generic binary tree might be declared as follows.
+type Tree[E any] struct {
+       left, right *Tree[E]
+       payload E
+}
+
+// A simple instantiation of Tree:
+var root1 Tree[int]
+
+// The actual type parameter provided may be a generic type itself:
+var root2 Tree[List[int]]
+
+// A couple of more complex examples.
+// We don't need extra parentheses around the element type of the slices on
+// the right (unlike when we use ()'s rather than []'s for type parameters).
+var _ List[List[int]] = []List[int]{}
+var _ List[List[List[Tree[int]]]] = []List[List[Tree[int]]]{}
+
+// Type parameters act like type aliases when used in generic types
+// in the sense that we can "emulate" a specific type instantiation
+// with type aliases.
+type T1[P any] struct {
+       f P
+}
+
+type T2[P any] struct {
+       f struct {
+               g P
+       }
+}
+
+var x1 T1[struct{ g int }]
+var x2 T2[int]
+
+func _() {
+       // This assignment is invalid because the types of x1, x2 are T1(...)
+       // and T2(...) respectively, which are two different defined types.
+       x1 = x2 // ERROR assignment
+
+       // This assignment is valid because the types of x1.f and x2.f are
+       // both struct { g int }; the type parameters act like type aliases
+       // and their actual names don't come into play here.
+       x1.f = x2.f
+}
+
+// We can verify this behavior using type aliases instead:
+type T1a struct {
+       f A1
+}
+type A1 = struct { g int }
+
+type T2a struct {
+       f struct {
+               g A2
+       }
+}
+type A2 = int
+
+var x1a T1a
+var x2a T2a
+
+func _() {
+       x1a = x2a // ERROR assignment
+       x1a.f = x2a.f
+}
+
+// Another interesting corner case are generic types that don't use
+// their type arguments. For instance:
+type T[P any] struct{}
+
+var xint T[int]
+var xbool T[bool]
+
+// Are these two variables of the same type? After all, their underlying
+// types are identical. We consider them to be different because each type
+// instantiation creates a new named type, in this case T<int> and T<bool>
+// even if their underlying types are identical. This is sensible because
+// we might still have methods that have different signatures or behave
+// differently depending on the type arguments, and thus we can't possibly
+// consider such types identical. Consequently:
+func _() {
+       xint = xbool // ERROR assignment
+}
+
+// Generic types cannot be used without instantiation.
+var _ T // ERROR cannot use generic type T
+
+// In type context, generic (parameterized) types cannot be parenthesized before
+// being instantiated. See also NOTES entry from 12/4/2019.
+var _ (T /* ERROR cannot use generic type T */ )[ /* ERROR unexpected \[ */ int]
+
+// All types may be parameterized, including interfaces.
+type I1[T any] interface{
+       m1(T)
+}
+
+// Generic interfaces may be embedded as one would expect.
+type I2 interface {
+       I1(int)     // method!
+       I1[string]  // embedded I1
+}
+
+func _() {
+       var x I2
+       x.I1(0)
+       x.m1("foo")
+}
+
+type I0 interface {
+       m0()
+}
+
+type I3 interface {
+       I0
+       I1[bool]
+       m(string)
+}
+
+func _() {
+       var x I3
+       x.m0()
+       x.m1(true)
+       x.m("foo")
+}
+
+type _ struct {
+       ( /* ERROR cannot parenthesize */ int8)
+       ( /* ERROR cannot parenthesize */ *int16)
+       *( /* ERROR cannot parenthesize */ int32)
+       List[int]
+
+       int8 /* ERROR int8 redeclared */
+       * /* ERROR int16 redeclared */ int16
+       List /* ERROR List redeclared */ [int]
+}
+
+// It's possible to declare local types whose underlying types
+// are type parameters. As with ordinary type definitions, the
+// types underlying properties are "inherited" but the methods
+// are not.
+func _[T interface{ m(); type int }]() {
+       type L T
+       var x L
+
+       // m is not defined on L (it is not "inherited" from
+       // its underlying type).
+       x.m /* ERROR x.m undefined */ ()
+
+       // But the properties of T, such that as that it supports
+       // the operations of the types given by its type bound,
+       // are also the properties of L.
+       x++
+       _ = x - x
+
+       // On the other hand, if we define a local alias for T,
+       // that alias stands for T as expected.
+       type A = T
+       var y A
+       y.m()
+       _ = y < 0
+}
+
+// As a special case, an explicit type argument may be omitted
+// from a type parameter bound if the type bound expects exactly
+// one type argument. In that case, the type argument is the
+// respective type parameter to which the type bound applies.
+// Note: We may not permit this syntactic sugar at first.
+// Note: This is now disabled. All examples below are adjusted.
+type Adder[T any] interface {
+       Add(T) T
+}
+
+// We don't need to explicitly instantiate the Adder bound
+// if we have exactly one type parameter.
+func Sum[T Adder[T]](list []T) T {
+       var sum T
+       for _, x := range list {
+               sum = sum.Add(x)
+       }
+       return sum
+}
+
+// Valid and invalid variations.
+type B0 interface {}
+type B1[_ any] interface{}
+type B2[_, _ any] interface{}
+
+func _[T1 B0]()
+func _[T1 B1[T1]]()
+func _[T1 B2 /* ERROR cannot use generic type .* without instantiation */ ]()
+
+func _[T1, T2 B0]()
+func _[T1 B1[T1], T2 B1[T2]]()
+func _[T1, T2 B2 /* ERROR cannot use generic type .* without instantiation */ ]()
+
+func _[T1 B0, T2 B1[T2]]() // here B1 applies to T2
+
+// When the type argument is left away, the type bound is
+// instantiated for each type parameter with that type
+// parameter.
+// Note: We may not permit this syntactic sugar at first.
+func _[A Adder[A], B Adder[B], C Adder[A]]() {
+       var a A // A's type bound is Adder[A]
+       a = a.Add(a)
+       var b B // B's type bound is Adder[B]
+       b = b.Add(b)
+       var c C // C's type bound is Adder[A]
+       a = c.Add(a)
+}
+
+// The type of variables (incl. parameters and return values) cannot
+// be an interface with type constraints or be/embed comparable.
+type I interface {
+       type int
+}
+
+var (
+       _ interface /* ERROR contains type constraints */ {type int}
+       _ I /* ERROR contains type constraints */
+)
+
+func _(I /* ERROR contains type constraints */ )
+func _(x, y, z I /* ERROR contains type constraints */ )
+func _() I /* ERROR contains type constraints */
+
+func _() {
+       var _ I /* ERROR contains type constraints */
+}
+
+type C interface {
+       comparable
+}
+
+var _ comparable /* ERROR comparable */
+var _ C /* ERROR comparable */
+
+func _(_ comparable /* ERROR comparable */ , _ C /* ERROR comparable */ )
+
+func _() {
+       var _ comparable /* ERROR comparable */
+       var _ C /* ERROR comparable */
+}
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go
new file mode 100644 (file)
index 0000000..34cbefc
--- /dev/null
@@ -0,0 +1,1969 @@
+// UNREVIEWED
+// Copyright 2012 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.
+
+// This file implements typechecking of expressions.
+
+package types2
+
+import (
+       "cmd/compile/internal/syntax"
+       "fmt"
+       "go/constant"
+       "go/token"
+       "math"
+)
+
+/*
+Basic algorithm:
+
+Expressions are checked recursively, top down. Expression checker functions
+are generally of the form:
+
+  func f(x *operand, e *syntax.Expr, ...)
+
+where e is the expression to be checked, and x is the result of the check.
+The check performed by f may fail in which case x.mode == invalid, and
+related error messages will have been issued by f.
+
+If a hint argument is present, it is the composite literal element type
+of an outer composite literal; it is used to type-check composite literal
+elements that have no explicit type specification in the source
+(e.g.: []T{{...}, {...}}, the hint is the type T in this case).
+
+All expressions are checked via rawExpr, which dispatches according
+to expression kind. Upon returning, rawExpr is recording the types and
+constant values for all expressions that have an untyped type (those types
+may change on the way up in the expression tree). Usually these are constants,
+but the results of comparisons or non-constant shifts of untyped constants
+may also be untyped, but not constant.
+
+Untyped expressions may eventually become fully typed (i.e., not untyped),
+typically when the value is assigned to a variable, or is used otherwise.
+The updateExprType method is used to record this final type and update
+the recorded types: the type-checked expression tree is again traversed down,
+and the new type is propagated as needed. Untyped constant expression values
+that become fully typed must now be representable by the full type (constant
+sub-expression trees are left alone except for their roots). This mechanism
+ensures that a client sees the actual (run-time) type an untyped value would
+have. It also permits type-checking of lhs shift operands "as if the shift
+were not present": when updateExprType visits an untyped lhs shift operand
+and assigns it it's final type, that type must be an integer type, and a
+constant lhs must be representable as an integer.
+
+When an expression gets its final type, either on the way out from rawExpr,
+on the way down in updateExprType, or at the end of the type checker run,
+the type (and constant value, if any) is recorded via Info.Types, if present.
+*/
+
+type opPredicates map[syntax.Operator]func(Type) bool
+
+var unaryOpPredicates = opPredicates{
+       syntax.Add: isNumeric,
+       syntax.Sub: isNumeric,
+       syntax.Xor: isInteger,
+       syntax.Not: isBoolean,
+}
+
+func (check *Checker) op(m opPredicates, x *operand, op syntax.Operator) bool {
+       if pred := m[op]; pred != nil {
+               if !pred(x.typ) {
+                       if check.conf.CompilerErrorMessages {
+                               check.invalidOpf(x, "operator %s not defined on %s", op, x)
+                       } else {
+                               check.invalidOpf(x, "operator %s not defined for %s", op, x)
+                       }
+                       return false
+               }
+       } else {
+               check.invalidASTf(x, "unknown operator %s", op)
+               return false
+       }
+       return true
+}
+
+func op2token(op syntax.Operator) token.Token {
+       switch op {
+       case syntax.Def: // :
+               unreachable()
+       case syntax.Not: // !
+               return token.NOT
+       case syntax.Recv: // <-
+               unreachable()
+
+       case syntax.OrOr: // ||
+               return token.LOR
+       case syntax.AndAnd: // &&
+               return token.LAND
+
+       case syntax.Eql: // ==
+               return token.EQL
+       case syntax.Neq: // !=
+               return token.NEQ
+       case syntax.Lss: // <
+               return token.LSS
+       case syntax.Leq: // <=
+               return token.LEQ
+       case syntax.Gtr: // >
+               return token.GTR
+       case syntax.Geq: // >=
+               return token.GEQ
+
+       case syntax.Add: // +
+               return token.ADD
+       case syntax.Sub: // -
+               return token.SUB
+       case syntax.Or: // |
+               return token.OR
+       case syntax.Xor: // ^
+               return token.XOR
+
+       case syntax.Mul: // *
+               return token.MUL
+       case syntax.Div: // /
+               return token.QUO
+       case syntax.Rem: // %
+               return token.REM
+       case syntax.And: // &
+               return token.AND
+       case syntax.AndNot: // &^
+               return token.AND_NOT
+       case syntax.Shl: // <<
+               return token.SHL
+       case syntax.Shr: // >>
+               return token.SHR
+       }
+
+       return token.ILLEGAL
+}
+
+// The unary expression e may be nil. It's passed in for better error messages only.
+func (check *Checker) unary(x *operand, e *syntax.Operation, op syntax.Operator) {
+       switch op {
+       case syntax.And:
+               // spec: "As an exception to the addressability
+               // requirement x may also be a composite literal."
+               if _, ok := unparen(x.expr).(*syntax.CompositeLit); !ok && x.mode != variable {
+                       check.invalidOpf(x, "cannot take address of %s", x)
+                       x.mode = invalid
+                       return
+               }
+               x.mode = value
+               x.typ = &Pointer{base: x.typ}
+               return
+
+       case syntax.Recv:
+               typ := x.typ.Chan()
+               if typ == nil {
+                       check.invalidOpf(x, "cannot receive from non-channel %s", x)
+                       x.mode = invalid
+                       return
+               }
+               if typ.dir == SendOnly {
+                       check.invalidOpf(x, "cannot receive from send-only channel %s", x)
+                       x.mode = invalid
+                       return
+               }
+               x.mode = commaok
+               x.typ = typ.elem
+               check.hasCallOrRecv = true
+               return
+       }
+
+       if !check.op(unaryOpPredicates, x, op) {
+               x.mode = invalid
+               return
+       }
+
+       if x.mode == constant_ {
+               typ := x.typ.Basic()
+               var prec uint
+               if isUnsigned(typ) {
+                       prec = uint(check.conf.sizeof(typ) * 8)
+               }
+               x.val = constant.UnaryOp(op2token(op), x.val, prec)
+               // Typed constants must be representable in
+               // their type after each constant operation.
+               if isTyped(typ) {
+                       if e != nil {
+                               x.expr = e // for better error message
+                       }
+                       check.representable(x, typ)
+               }
+               return
+       }
+
+       x.mode = value
+       // x.typ remains unchanged
+}
+
+func isShift(op syntax.Operator) bool {
+       return op == syntax.Shl || op == syntax.Shr
+}
+
+func isComparison(op syntax.Operator) bool {
+       // Note: tokens are not ordered well to make this much easier
+       switch op {
+       case syntax.Eql, syntax.Neq, syntax.Lss, syntax.Leq, syntax.Gtr, syntax.Geq:
+               return true
+       }
+       return false
+}
+
+func fitsFloat32(x constant.Value) bool {
+       f32, _ := constant.Float32Val(x)
+       f := float64(f32)
+       return !math.IsInf(f, 0)
+}
+
+func roundFloat32(x constant.Value) constant.Value {
+       f32, _ := constant.Float32Val(x)
+       f := float64(f32)
+       if !math.IsInf(f, 0) {
+               return constant.MakeFloat64(f)
+       }
+       return nil
+}
+
+func fitsFloat64(x constant.Value) bool {
+       f, _ := constant.Float64Val(x)
+       return !math.IsInf(f, 0)
+}
+
+func roundFloat64(x constant.Value) constant.Value {
+       f, _ := constant.Float64Val(x)
+       if !math.IsInf(f, 0) {
+               return constant.MakeFloat64(f)
+       }
+       return nil
+}
+
+// representableConst reports whether x can be represented as
+// value of the given basic type and for the configuration
+// provided (only needed for int/uint sizes).
+//
+// If rounded != nil, *rounded is set to the rounded value of x for
+// representable floating-point and complex values, and to an Int
+// value for integer values; it is left alone otherwise.
+// It is ok to provide the addressof the first argument for rounded.
+//
+// The check parameter may be nil if representableConst is invoked
+// (indirectly) through an exported API call (AssignableTo, ConvertibleTo)
+// because we don't need the Checker's config for those calls.
+func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *constant.Value) bool {
+       if x.Kind() == constant.Unknown {
+               return true // avoid follow-up errors
+       }
+
+       var conf *Config
+       if check != nil {
+               conf = check.conf
+       }
+
+       switch {
+       case isInteger(typ):
+               x := constant.ToInt(x)
+               if x.Kind() != constant.Int {
+                       return false
+               }
+               if rounded != nil {
+                       *rounded = x
+               }
+               if x, ok := constant.Int64Val(x); ok {
+                       switch typ.kind {
+                       case Int:
+                               var s = uint(conf.sizeof(typ)) * 8
+                               return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
+                       case Int8:
+                               const s = 8
+                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+                       case Int16:
+                               const s = 16
+                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+                       case Int32:
+                               const s = 32
+                               return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+                       case Int64, UntypedInt:
+                               return true
+                       case Uint, Uintptr:
+                               if s := uint(conf.sizeof(typ)) * 8; s < 64 {
+                                       return 0 <= x && x <= int64(1)<<s-1
+                               }
+                               return 0 <= x
+                       case Uint8:
+                               const s = 8
+                               return 0 <= x && x <= 1<<s-1
+                       case Uint16:
+                               const s = 16
+                               return 0 <= x && x <= 1<<s-1
+                       case Uint32:
+                               const s = 32
+                               return 0 <= x && x <= 1<<s-1
+                       case Uint64:
+                               return 0 <= x
+                       default:
+                               unreachable()
+                       }
+               }
+               // x does not fit into int64
+               switch n := constant.BitLen(x); typ.kind {
+               case Uint, Uintptr:
+                       var s = uint(conf.sizeof(typ)) * 8
+                       return constant.Sign(x) >= 0 && n <= int(s)
+               case Uint64:
+                       return constant.Sign(x) >= 0 && n <= 64
+               case UntypedInt:
+                       return true
+               }
+
+       case isFloat(typ):
+               x := constant.ToFloat(x)
+               if x.Kind() != constant.Float {
+                       return false
+               }
+               switch typ.kind {
+               case Float32:
+                       if rounded == nil {
+                               return fitsFloat32(x)
+                       }
+                       r := roundFloat32(x)
+                       if r != nil {
+                               *rounded = r
+                               return true
+                       }
+               case Float64:
+                       if rounded == nil {
+                               return fitsFloat64(x)
+                       }
+                       r := roundFloat64(x)
+                       if r != nil {
+                               *rounded = r
+                               return true
+                       }
+               case UntypedFloat:
+                       return true
+               default:
+                       unreachable()
+               }
+
+       case isComplex(typ):
+               x := constant.ToComplex(x)
+               if x.Kind() != constant.Complex {
+                       return false
+               }
+               switch typ.kind {
+               case Complex64:
+                       if rounded == nil {
+                               return fitsFloat32(constant.Real(x)) && fitsFloat32(constant.Imag(x))
+                       }
+                       re := roundFloat32(constant.Real(x))
+                       im := roundFloat32(constant.Imag(x))
+                       if re != nil && im != nil {
+                               *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
+                               return true
+                       }
+               case Complex128:
+                       if rounded == nil {
+                               return fitsFloat64(constant.Real(x)) && fitsFloat64(constant.Imag(x))
+                       }
+                       re := roundFloat64(constant.Real(x))
+                       im := roundFloat64(constant.Imag(x))
+                       if re != nil && im != nil {
+                               *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
+                               return true
+                       }
+               case UntypedComplex:
+                       return true
+               default:
+                       unreachable()
+               }
+
+       case isString(typ):
+               return x.Kind() == constant.String
+
+       case isBoolean(typ):
+               return x.Kind() == constant.Bool
+       }
+
+       return false
+}
+
+// representable checks that a constant operand is representable in the given basic type.
+func (check *Checker) representable(x *operand, typ *Basic) {
+       assert(x.mode == constant_)
+       if !representableConst(x.val, check, typ, &x.val) {
+               var msg string
+               if isNumeric(x.typ) && isNumeric(typ) {
+                       // numeric conversion : error msg
+                       //
+                       // integer -> integer : overflows
+                       // integer -> float   : overflows (actually not possible)
+                       // float   -> integer : truncated
+                       // float   -> float   : overflows
+                       //
+                       if !isInteger(x.typ) && isInteger(typ) {
+                               msg = "%s truncated to %s"
+                       } else {
+                               msg = "%s overflows %s"
+                       }
+               } else {
+                       msg = "cannot convert %s to %s"
+               }
+               check.errorf(x, msg, x, typ)
+               x.mode = invalid
+       }
+}
+
+// updateExprType updates the type of x to typ and invokes itself
+// recursively for the operands of x, depending on expression kind.
+// If typ is still an untyped and not the final type, updateExprType
+// only updates the recorded untyped type for x and possibly its
+// operands. Otherwise (i.e., typ is not an untyped type anymore,
+// or it is the final type for x), the type and value are recorded.
+// Also, if x is a constant, it must be representable as a value of typ,
+// and if x is the (formerly untyped) lhs operand of a non-constant
+// shift, it must be an integer value.
+//
+func (check *Checker) updateExprType(x syntax.Expr, typ Type, final bool) {
+       old, found := check.untyped[x]
+       if !found {
+               return // nothing to do
+       }
+
+       // update operands of x if necessary
+       switch x := x.(type) {
+       case *syntax.BadExpr,
+               *syntax.FuncLit,
+               *syntax.CompositeLit,
+               *syntax.IndexExpr,
+               *syntax.SliceExpr,
+               *syntax.AssertExpr,
+               //*syntax.StarExpr,
+               *syntax.KeyValueExpr,
+               *syntax.ArrayType,
+               *syntax.StructType,
+               *syntax.FuncType,
+               *syntax.InterfaceType,
+               *syntax.MapType,
+               *syntax.ChanType:
+               // These expression are never untyped - nothing to do.
+               // The respective sub-expressions got their final types
+               // upon assignment or use.
+               if debug {
+                       check.dump("%v: found old type(%s): %s (new: %s)", posFor(x), x, old.typ, typ)
+                       unreachable()
+               }
+               return
+
+       case *syntax.CallExpr:
+               // Resulting in an untyped constant (e.g., built-in complex).
+               // The respective calls take care of calling updateExprType
+               // for the arguments if necessary.
+
+       case *syntax.Name, *syntax.BasicLit, *syntax.SelectorExpr:
+               // An identifier denoting a constant, a constant literal,
+               // or a qualified identifier (imported untyped constant).
+               // No operands to take care of.
+
+       case *syntax.ParenExpr:
+               check.updateExprType(x.X, typ, final)
+
+       // case *syntax.UnaryExpr:
+       //      // If x is a constant, the operands were constants.
+       //      // The operands don't need to be updated since they
+       //      // never get "materialized" into a typed value. If
+       //      // left in the untyped map, they will be processed
+       //      // at the end of the type check.
+       //      if old.val != nil {
+       //              break
+       //      }
+       //      check.updateExprType(x.X, typ, final)
+
+       case *syntax.Operation:
+               if x.Y == nil {
+                       // unary expression
+                       if x.Op == syntax.Mul {
+                               // see commented out code for StarExpr above
+                               // TODO(gri) needs cleanup
+                               if debug {
+                                       unimplemented()
+                               }
+                               return
+                       }
+                       // If x is a constant, the operands were constants.
+                       // The operands don't need to be updated since they
+                       // never get "materialized" into a typed value. If
+                       // left in the untyped map, they will be processed
+                       // at the end of the type check.
+                       if old.val != nil {
+                               break
+                       }
+                       check.updateExprType(x.X, typ, final)
+                       break
+               }
+
+               // binary expression
+               if old.val != nil {
+                       break // see comment for unary expressions
+               }
+               if isComparison(x.Op) {
+                       // The result type is independent of operand types
+                       // and the operand types must have final types.
+               } else if isShift(x.Op) {
+                       // The result type depends only on lhs operand.
+                       // The rhs type was updated when checking the shift.
+                       check.updateExprType(x.X, typ, final)
+               } else {
+                       // The operand types match the result type.
+                       check.updateExprType(x.X, typ, final)
+                       check.updateExprType(x.Y, typ, final)
+               }
+
+       default:
+               unreachable()
+       }
+
+       // If the new type is not final and still untyped, just
+       // update the recorded type.
+       if !final && isUntyped(typ) {
+               old.typ = typ.Basic()
+               check.untyped[x] = old
+               return
+       }
+
+       // Otherwise we have the final (typed or untyped type).
+       // Remove it from the map of yet untyped expressions.
+       delete(check.untyped, x)
+
+       if old.isLhs {
+               // If x is the lhs of a shift, its final type must be integer.
+               // We already know from the shift check that it is representable
+               // as an integer if it is a constant.
+               if !isInteger(typ) {
+                       check.invalidOpf(x, "shifted operand %s (type %s) must be integer", x, typ)
+                       return
+               }
+               // Even if we have an integer, if the value is a constant we
+               // still must check that it is representable as the specific
+               // int type requested (was issue #22969). Fall through here.
+       }
+       if old.val != nil {
+               // If x is a constant, it must be representable as a value of typ.
+               c := operand{old.mode, x, old.typ, old.val, 0}
+               check.convertUntyped(&c, typ)
+               if c.mode == invalid {
+                       return
+               }
+       }
+
+       // Everything's fine, record final type and value for x.
+       check.recordTypeAndValue(x, old.mode, typ, old.val)
+}
+
+// updateExprVal updates the value of x to val.
+func (check *Checker) updateExprVal(x syntax.Expr, val constant.Value) {
+       if info, ok := check.untyped[x]; ok {
+               info.val = val
+               check.untyped[x] = info
+       }
+}
+
+// convertUntyped attempts to set the type of an untyped value to the target type.
+func (check *Checker) convertUntyped(x *operand, target Type) {
+       target = expand(target)
+       if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
+               return
+       }
+
+       // TODO(gri) Sloppy code - clean up. This function is central
+       //           to assignment and expression checking.
+
+       if isUntyped(target) {
+               // both x and target are untyped
+               xkind := x.typ.(*Basic).kind
+               tkind := target.(*Basic).kind
+               if isNumeric(x.typ) && isNumeric(target) {
+                       if xkind < tkind {
+                               x.typ = target
+                               check.updateExprType(x.expr, target, false)
+                       }
+               } else if xkind != tkind {
+                       goto Error
+               }
+               return
+       }
+
+       // In case of a type parameter, conversion must succeed against
+       // all types enumerated by the type parameter bound.
+       // TODO(gri) We should not need this because we have the code
+       // for Sum types in convertUntypedInternal. But at least one
+       // test fails. Investigate.
+       if t := target.TypeParam(); t != nil {
+               types := t.Bound().allTypes
+               if types == nil {
+                       goto Error
+               }
+
+               for _, t := range unpack(types) {
+                       check.convertUntypedInternal(x, t)
+                       if x.mode == invalid {
+                               goto Error
+                       }
+               }
+
+               // keep nil untyped (was bug #39755)
+               if x.isNil() {
+                       target = Typ[UntypedNil]
+               }
+               x.typ = target
+               check.updateExprType(x.expr, target, true) // UntypedNils are final
+               return
+       }
+
+       check.convertUntypedInternal(x, target)
+       return
+
+Error:
+       // TODO(gri) better error message (explain cause)
+       check.errorf(x, "cannot convert %s to %s", x, target)
+       x.mode = invalid
+}
+
+// convertUntypedInternal should only be called by convertUntyped.
+func (check *Checker) convertUntypedInternal(x *operand, target Type) {
+       assert(isTyped(target))
+
+       // typed target
+       switch t := optype(target.Under()).(type) {
+       case *Basic:
+               if x.mode == constant_ {
+                       check.representable(x, t)
+                       if x.mode == invalid {
+                               return
+                       }
+                       // expression value may have been rounded - update if needed
+                       check.updateExprVal(x.expr, x.val)
+               } else {
+                       // Non-constant untyped values may appear as the
+                       // result of comparisons (untyped bool), intermediate
+                       // (delayed-checked) rhs operands of shifts, and as
+                       // the value nil.
+                       switch x.typ.(*Basic).kind {
+                       case UntypedBool:
+                               if !isBoolean(target) {
+                                       goto Error
+                               }
+                       case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex:
+                               if !isNumeric(target) {
+                                       goto Error
+                               }
+                       case UntypedString:
+                               // Non-constant untyped string values are not
+                               // permitted by the spec and should not occur.
+                               unreachable()
+                       case UntypedNil:
+                               // Unsafe.Pointer is a basic type that includes nil.
+                               if !hasNil(target) {
+                                       goto Error
+                               }
+                       default:
+                               goto Error
+                       }
+               }
+       case *Sum:
+               t.is(func(t Type) bool {
+                       check.convertUntypedInternal(x, t)
+                       return x.mode != invalid
+               })
+       case *Interface:
+               // Update operand types to the default type rather then
+               // the target (interface) type: values must have concrete
+               // dynamic types. If the value is nil, keep it untyped
+               // (this is important for tools such as go vet which need
+               // the dynamic type for argument checking of say, print
+               // functions)
+               if x.isNil() {
+                       target = Typ[UntypedNil]
+               } else {
+                       // cannot assign untyped values to non-empty interfaces
+                       check.completeInterface(nopos, t)
+                       if !t.Empty() {
+                               goto Error
+                       }
+                       target = Default(x.typ)
+               }
+       case *Pointer, *Signature, *Slice, *Map, *Chan:
+               if !x.isNil() {
+                       goto Error
+               }
+               // keep nil untyped - see comment for interfaces, above
+               target = Typ[UntypedNil]
+       default:
+               goto Error
+       }
+
+       x.typ = target
+       check.updateExprType(x.expr, target, true) // UntypedNils are final
+       return
+
+Error:
+       check.errorf(x, "cannot convert %s to %s", x, target)
+       x.mode = invalid
+}
+
+func (check *Checker) comparison(x, y *operand, op syntax.Operator) {
+       // spec: "In any comparison, the first operand must be assignable
+       // to the type of the second operand, or vice versa."
+       err := ""
+       if x.assignableTo(check, y.typ, nil) || y.assignableTo(check, x.typ, nil) {
+               defined := false
+               switch op {
+               case syntax.Eql, syntax.Neq:
+                       // spec: "The equality operators == and != apply to operands that are comparable."
+                       defined = Comparable(x.typ) && Comparable(y.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
+               case syntax.Lss, syntax.Leq, syntax.Gtr, syntax.Geq:
+                       // spec: The ordering operators <, <=, >, and >= apply to operands that are ordered."
+                       defined = isOrdered(x.typ) && isOrdered(y.typ)
+               default:
+                       unreachable()
+               }
+               if !defined {
+                       typ := x.typ
+                       if x.isNil() {
+                               typ = y.typ
+                       }
+                       if check.conf.CompilerErrorMessages {
+                               err = check.sprintf("operator %s not defined on %s", op, typ)
+                       } else {
+                               err = check.sprintf("operator %s not defined for %s", op, typ)
+                       }
+               }
+       } else {
+               err = check.sprintf("mismatched types %s and %s", x.typ, y.typ)
+       }
+
+       if err != "" {
+               // TODO(gri) better error message for cases where one can only compare against nil
+               check.invalidOpf(x, "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err)
+               x.mode = invalid
+               return
+       }
+
+       if x.mode == constant_ && y.mode == constant_ {
+               x.val = constant.MakeBool(constant.Compare(x.val, op2token(op), y.val))
+               // The operands are never materialized; no need to update
+               // their types.
+       } else {
+               x.mode = value
+               // The operands have now their final types, which at run-
+               // time will be materialized. Update the expression trees.
+               // If the current types are untyped, the materialized type
+               // is the respective default type.
+               check.updateExprType(x.expr, Default(x.typ), true)
+               check.updateExprType(y.expr, Default(y.typ), true)
+       }
+
+       // spec: "Comparison operators compare two operands and yield
+       //        an untyped boolean value."
+       x.typ = Typ[UntypedBool]
+}
+
+func (check *Checker) shift(x, y *operand, e *syntax.Operation, op syntax.Operator) {
+       untypedx := isUntyped(x.typ)
+
+       var xval constant.Value
+       if x.mode == constant_ {
+               xval = constant.ToInt(x.val)
+       }
+
+       if isInteger(x.typ) || untypedx && xval != nil && xval.Kind() == constant.Int {
+               // The lhs is of integer type or an untyped constant representable
+               // as an integer. Nothing to do.
+       } else {
+               // shift has no chance
+               check.invalidOpf(x, "shifted operand %s must be integer", x)
+               x.mode = invalid
+               return
+       }
+
+       // spec: "The right operand in a shift expression must have integer type
+       // or be an untyped constant representable by a value of type uint."
+       switch {
+       case isInteger(y.typ):
+               // nothing to do
+       case isUntyped(y.typ):
+               check.convertUntyped(y, Typ[Uint])
+               if y.mode == invalid {
+                       x.mode = invalid
+                       return
+               }
+       default:
+               check.invalidOpf(y, "shift count %s must be integer", y)
+               x.mode = invalid
+               return
+       }
+
+       var yval constant.Value
+       if y.mode == constant_ {
+               // rhs must be an integer value
+               // (Either it was of an integer type already, or it was
+               // untyped and successfully converted to a uint above.)
+               yval = constant.ToInt(y.val)
+               assert(yval.Kind() == constant.Int)
+               if constant.Sign(yval) < 0 {
+                       check.invalidOpf(y, "negative shift count %s", y)
+                       x.mode = invalid
+                       return
+               }
+       }
+
+       if x.mode == constant_ {
+               if y.mode == constant_ {
+                       // rhs must be within reasonable bounds in constant shifts
+                       const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64
+                       s, ok := constant.Uint64Val(yval)
+                       if !ok || s > shiftBound {
+                               check.invalidOpf(y, "invalid shift count %s", y)
+                               x.mode = invalid
+                               return
+                       }
+                       // The lhs is representable as an integer but may not be an integer
+                       // (e.g., 2.0, an untyped float) - this can only happen for untyped
+                       // non-integer numeric constants. Correct the type so that the shift
+                       // result is of integer type.
+                       if !isInteger(x.typ) {
+                               x.typ = Typ[UntypedInt]
+                       }
+                       // x is a constant so xval != nil and it must be of Int kind.
+                       x.val = constant.Shift(xval, op2token(op), uint(s))
+                       // Typed constants must be representable in
+                       // their type after each constant operation.
+                       if isTyped(x.typ) {
+                               if e != nil {
+                                       x.expr = e // for better error message
+                               }
+                               check.representable(x, x.typ.Basic())
+                       }
+                       return
+               }
+
+               // non-constant shift with constant lhs
+               if untypedx {
+                       // spec: "If the left operand of a non-constant shift
+                       // expression is an untyped constant, the type of the
+                       // constant is what it would be if the shift expression
+                       // were replaced by its left operand alone.".
+                       //
+                       // Delay operand checking until we know the final type
+                       // by marking the lhs expression as lhs shift operand.
+                       //
+                       // Usually (in correct programs), the lhs expression
+                       // is in the untyped map. However, it is possible to
+                       // create incorrect programs where the same expression
+                       // is evaluated twice (via a declaration cycle) such
+                       // that the lhs expression type is determined in the
+                       // first round and thus deleted from the map, and then
+                       // not found in the second round (double insertion of
+                       // the same expr node still just leads to one entry for
+                       // that node, and it can only be deleted once).
+                       // Be cautious and check for presence of entry.
+                       // Example: var e, f = int(1<<""[f]) // issue 11347
+                       if info, found := check.untyped[x.expr]; found {
+                               info.isLhs = true
+                               check.untyped[x.expr] = info
+                       }
+                       // keep x's type
+                       x.mode = value
+                       return
+               }
+       }
+
+       // non-constant shift - lhs must be an integer
+       if !isInteger(x.typ) {
+               check.invalidOpf(x, "shifted operand %s must be integer", x)
+               x.mode = invalid
+               return
+       }
+
+       x.mode = value
+}
+
+var binaryOpPredicates = opPredicates{
+       syntax.Add: isNumericOrString,
+       syntax.Sub: isNumeric,
+       syntax.Mul: isNumeric,
+       syntax.Div: isNumeric,
+       syntax.Rem: isInteger,
+
+       syntax.And:    isInteger,
+       syntax.Or:     isInteger,
+       syntax.Xor:    isInteger,
+       syntax.AndNot: isInteger,
+
+       syntax.AndAnd: isBoolean,
+       syntax.OrOr:   isBoolean,
+}
+
+// The binary expression e may be nil. It's passed in for better error messages only.
+func (check *Checker) binary(x *operand, e *syntax.Operation, lhs, rhs syntax.Expr, op syntax.Operator, opPos syntax.Pos) {
+       var y operand
+
+       check.expr(x, lhs)
+       check.expr(&y, rhs)
+
+       if x.mode == invalid {
+               return
+       }
+       if y.mode == invalid {
+               x.mode = invalid
+               x.expr = y.expr
+               return
+       }
+
+       if isShift(op) {
+               check.shift(x, &y, e, op)
+               return
+       }
+
+       check.convertUntyped(x, y.typ)
+       if x.mode == invalid {
+               return
+       }
+       check.convertUntyped(&y, x.typ)
+       if y.mode == invalid {
+               x.mode = invalid
+               return
+       }
+
+       if isComparison(op) {
+               check.comparison(x, &y, op)
+               return
+       }
+
+       if !check.identical(x.typ, y.typ) {
+               // only report an error if we have valid types
+               // (otherwise we had an error reported elsewhere already)
+               if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
+                       check.invalidOpf(x, "mismatched types %s and %s", x.typ, y.typ)
+               }
+               x.mode = invalid
+               return
+       }
+
+       if !check.op(binaryOpPredicates, x, op) {
+               x.mode = invalid
+               return
+       }
+
+       if op == syntax.Div || op == syntax.Rem {
+               // check for zero divisor
+               if (x.mode == constant_ || isInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
+                       check.invalidOpf(&y, "division by zero")
+                       x.mode = invalid
+                       return
+               }
+
+               // check for divisor underflow in complex division (see issue 20227)
+               if x.mode == constant_ && y.mode == constant_ && isComplex(x.typ) {
+                       re, im := constant.Real(y.val), constant.Imag(y.val)
+                       re2, im2 := constant.BinaryOp(re, token.MUL, re), constant.BinaryOp(im, token.MUL, im)
+                       if constant.Sign(re2) == 0 && constant.Sign(im2) == 0 {
+                               check.invalidOpf(&y, "division by zero")
+                               x.mode = invalid
+                               return
+                       }
+               }
+       }
+
+       if x.mode == constant_ && y.mode == constant_ {
+               xval := x.val
+               yval := y.val
+               typ := x.typ.Basic()
+               // force integer division of integer operands
+               tok := op2token(op)
+               if op == syntax.Div && isInteger(typ) {
+                       tok = token.QUO_ASSIGN
+               }
+               x.val = constant.BinaryOp(xval, tok, yval)
+               // report error if valid operands lead to an invalid result
+               if xval.Kind() != constant.Unknown && yval.Kind() != constant.Unknown && x.val.Kind() == constant.Unknown {
+                       // TODO(gri) We should report exactly what went wrong. At the
+                       //           moment we don't have the (go/constant) API for that.
+                       //           See also TODO in go/constant/value.go.
+                       check.errorf(opPos, "constant result is not representable")
+                       // TODO(gri) Should we mark operands with unknown values as invalid?
+               }
+               // Typed constants must be representable in
+               // their type after each constant operation.
+               if isTyped(typ) {
+                       if e != nil {
+                               x.expr = e // for better error message
+                       }
+                       check.representable(x, typ)
+               }
+               return
+       }
+
+       x.mode = value
+       // x.typ is unchanged
+}
+
+// index checks an index expression for validity.
+// If max >= 0, it is the upper bound for index.
+// If the result typ is != Typ[Invalid], index is valid and typ is its (possibly named) integer type.
+// If the result val >= 0, index is valid and val is its constant int value.
+func (check *Checker) index(index syntax.Expr, max int64) (typ Type, val int64) {
+       typ = Typ[Invalid]
+       val = -1
+
+       var x operand
+       check.expr(&x, index)
+       if x.mode == invalid {
+               return
+       }
+
+       // an untyped constant must be representable as Int
+       check.convertUntyped(&x, Typ[Int])
+       if x.mode == invalid {
+               return
+       }
+
+       // the index must be of integer type
+       if !isInteger(x.typ) {
+               check.invalidArgf(&x, "index %s must be integer", &x)
+               return
+       }
+
+       if x.mode != constant_ {
+               return x.typ, -1
+       }
+
+       // a constant index i must be in bounds
+       if constant.Sign(x.val) < 0 {
+               check.invalidArgf(&x, "index %s must not be negative", &x)
+               return
+       }
+
+       v, valid := constant.Int64Val(constant.ToInt(x.val))
+       if !valid || max >= 0 && v >= max {
+               if check.conf.CompilerErrorMessages {
+                       check.errorf(&x, "array index %s out of bounds [0:%d]", x.val.String(), max)
+               } else {
+                       check.errorf(&x, "index %s is out of bounds", &x)
+               }
+               return
+       }
+
+       // 0 <= v [ && v < max ]
+       return Typ[Int], v
+}
+
+// indexElts checks the elements (elts) of an array or slice composite literal
+// against the literal's element type (typ), and the element indices against
+// the literal length if known (length >= 0). It returns the length of the
+// literal (maximum index value + 1).
+//
+func (check *Checker) indexedElts(elts []syntax.Expr, typ Type, length int64) int64 {
+       visited := make(map[int64]bool, len(elts))
+       var index, max int64
+       for _, e := range elts {
+               // determine and check index
+               validIndex := false
+               eval := e
+               if kv, _ := e.(*syntax.KeyValueExpr); kv != nil {
+                       if typ, i := check.index(kv.Key, length); typ != Typ[Invalid] {
+                               if i >= 0 {
+                                       index = i
+                                       validIndex = true
+                               } else {
+                                       check.errorf(e, "index %s must be integer constant", kv.Key)
+                               }
+                       }
+                       eval = kv.Value
+               } else if length >= 0 && index >= length {
+                       check.errorf(e, "index %d is out of bounds (>= %d)", index, length)
+               } else {
+                       validIndex = true
+               }
+
+               // if we have a valid index, check for duplicate entries
+               if validIndex {
+                       if visited[index] {
+                               check.errorf(e, "duplicate index %d in array or slice literal", index)
+                       }
+                       visited[index] = true
+               }
+               index++
+               if index > max {
+                       max = index
+               }
+
+               // check element against composite literal element type
+               var x operand
+               check.exprWithHint(&x, eval, typ)
+               check.assignment(&x, typ, "array or slice literal")
+       }
+       return max
+}
+
+// exprKind describes the kind of an expression; the kind
+// determines if an expression is valid in 'statement context'.
+type exprKind int
+
+const (
+       conversion exprKind = iota
+       expression
+       statement
+)
+
+// rawExpr typechecks expression e and initializes x with the expression
+// value or type. If an error occurred, x.mode is set to invalid.
+// If hint != nil, it is the type of a composite literal element.
+//
+func (check *Checker) rawExpr(x *operand, e syntax.Expr, hint Type) exprKind {
+       if check.conf.Trace {
+               check.trace(e.Pos(), "expr %s", e)
+               check.indent++
+               defer func() {
+                       check.indent--
+                       check.trace(e.Pos(), "=> %s", x)
+               }()
+       }
+
+       kind := check.exprInternal(x, e, hint)
+
+       // convert x into a user-friendly set of values
+       // TODO(gri) this code can be simplified
+       var typ Type
+       var val constant.Value
+       switch x.mode {
+       case invalid:
+               typ = Typ[Invalid]
+       case novalue:
+               typ = (*Tuple)(nil)
+       case constant_:
+               typ = x.typ
+               val = x.val
+       default:
+               typ = x.typ
+       }
+       assert(x.expr != nil && typ != nil)
+
+       if isUntyped(typ) {
+               // delay type and value recording until we know the type
+               // or until the end of type checking
+               check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
+       } else {
+               check.recordTypeAndValue(e, x.mode, typ, val)
+       }
+
+       return kind
+}
+
+// exprInternal contains the core of type checking of expressions.
+// Must only be called by rawExpr.
+//
+func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKind {
+       // make sure x has a valid state in case of bailout
+       // (was issue 5770)
+       x.mode = invalid
+       x.typ = Typ[Invalid]
+
+       switch e := e.(type) {
+       case nil:
+               unreachable()
+
+       case *syntax.BadExpr:
+               goto Error // error was reported before
+
+       case *syntax.Name:
+               check.ident(x, e, nil, false)
+
+       case *syntax.DotsType:
+               // ellipses are handled explicitly where they are legal
+               // (array composite literals and parameter lists)
+               check.error(e, "invalid use of '...'")
+               goto Error
+
+       case *syntax.BasicLit:
+               if e.Bad {
+                       goto Error // error reported during parsing
+               }
+               x.setConst(e.Kind, e.Value)
+               if x.mode == invalid {
+                       // The parser already establishes syntactic correctness.
+                       // If we reach here it's because of number under-/overflow.
+                       // TODO(gri) setConst (and in turn the go/constant package)
+                       // should return an error describing the issue.
+                       check.errorf(e, "malformed constant: %s", e.Value)
+                       goto Error
+               }
+
+       case *syntax.FuncLit:
+               if sig, ok := check.typ(e.Type).(*Signature); ok {
+                       // Anonymous functions are considered part of the
+                       // init expression/func declaration which contains
+                       // them: use existing package-level declaration info.
+                       decl := check.decl // capture for use in closure below
+                       iota := check.iota // capture for use in closure below (#22345)
+                       // Don't type-check right away because the function may
+                       // be part of a type definition to which the function
+                       // body refers. Instead, type-check as soon as possible,
+                       // but before the enclosing scope contents changes (#22992).
+                       check.later(func() {
+                               check.funcBody(decl, "<function literal>", sig, e.Body, iota)
+                       })
+                       x.mode = value
+                       x.typ = sig
+               } else {
+                       check.invalidASTf(e, "invalid function literal %s", e)
+                       goto Error
+               }
+
+       case *syntax.CompositeLit:
+               var typ, base Type
+
+               switch {
+               case e.Type != nil:
+                       // composite literal type present - use it
+                       // [...]T array types may only appear with composite literals.
+                       // Check for them here so we don't have to handle ... in general.
+                       if atyp, _ := e.Type.(*syntax.ArrayType); atyp != nil && atyp.Len == nil {
+                               // We have an "open" [...]T array type.
+                               // Create a new ArrayType with unknown length (-1)
+                               // and finish setting it up after analyzing the literal.
+                               typ = &Array{len: -1, elem: check.varType(atyp.Elem)}
+                               base = typ
+                               break
+                       }
+                       typ = check.typ(e.Type)
+                       base = typ
+
+               case hint != nil:
+                       // no composite literal type present - use hint (element type of enclosing type)
+                       typ = hint
+                       base, _ = deref(typ.Under()) // *T implies &T{}
+
+               default:
+                       // TODO(gri) provide better error messages depending on context
+                       check.error(e, "missing type in composite literal")
+                       goto Error
+               }
+
+               switch utyp := optype(base.Under()).(type) {
+               case *Struct:
+                       if len(e.ElemList) == 0 {
+                               break
+                       }
+                       fields := utyp.fields
+                       if _, ok := e.ElemList[0].(*syntax.KeyValueExpr); ok {
+                               // all elements must have keys
+                               visited := make([]bool, len(fields))
+                               for _, e := range e.ElemList {
+                                       kv, _ := e.(*syntax.KeyValueExpr)
+                                       if kv == nil {
+                                               check.error(e, "mixture of field:value and value elements in struct literal")
+                                               continue
+                                       }
+                                       key, _ := kv.Key.(*syntax.Name)
+                                       // do all possible checks early (before exiting due to errors)
+                                       // so we don't drop information on the floor
+                                       check.expr(x, kv.Value)
+                                       if key == nil {
+                                               check.errorf(kv, "invalid field name %s in struct literal", kv.Key)
+                                               continue
+                                       }
+                                       i := fieldIndex(utyp.fields, check.pkg, key.Value)
+                                       if i < 0 {
+                                               if check.conf.CompilerErrorMessages {
+                                                       check.errorf(kv.Key, "unknown field '%s' in struct literal of type %s", key.Value, base)
+                                               } else {
+                                                       check.errorf(kv.Key, "unknown field %s in struct literal", key.Value)
+                                               }
+                                               continue
+                                       }
+                                       fld := fields[i]
+                                       check.recordUse(key, fld)
+                                       etyp := fld.typ
+                                       check.assignment(x, etyp, "struct literal")
+                                       // 0 <= i < len(fields)
+                                       if visited[i] {
+                                               check.errorf(kv, "duplicate field name %s in struct literal", key.Value)
+                                               continue
+                                       }
+                                       visited[i] = true
+                               }
+                       } else {
+                               // no element must have a key
+                               for i, e := range e.ElemList {
+                                       if kv, _ := e.(*syntax.KeyValueExpr); kv != nil {
+                                               check.error(kv, "mixture of field:value and value elements in struct literal")
+                                               continue
+                                       }
+                                       check.expr(x, e)
+                                       if i >= len(fields) {
+                                               check.error(x, "too many values in struct literal")
+                                               break // cannot continue
+                                       }
+                                       // i < len(fields)
+                                       fld := fields[i]
+                                       if !fld.Exported() && fld.pkg != check.pkg {
+                                               check.errorf(x, "implicit assignment to unexported field %s in %s literal", fld.name, typ)
+                                               continue
+                                       }
+                                       etyp := fld.typ
+                                       check.assignment(x, etyp, "struct literal")
+                               }
+                               if len(e.ElemList) < len(fields) {
+                                       check.error(e.Rbrace, "too few values in struct literal")
+                                       // ok to continue
+                               }
+                       }
+
+               case *Array:
+                       // Prevent crash if the array referred to is not yet set up. Was issue #18643.
+                       // This is a stop-gap solution. Should use Checker.objPath to report entire
+                       // path starting with earliest declaration in the source. TODO(gri) fix this.
+                       if utyp.elem == nil {
+                               check.error(e, "illegal cycle in type declaration")
+                               goto Error
+                       }
+                       n := check.indexedElts(e.ElemList, utyp.elem, utyp.len)
+                       // If we have an array of unknown length (usually [...]T arrays, but also
+                       // arrays [n]T where n is invalid) set the length now that we know it and
+                       // record the type for the array (usually done by check.typ which is not
+                       // called for [...]T). We handle [...]T arrays and arrays with invalid
+                       // length the same here because it makes sense to "guess" the length for
+                       // the latter if we have a composite literal; e.g. for [n]int{1, 2, 3}
+                       // where n is invalid for some reason, it seems fair to assume it should
+                       // be 3 (see also Checked.arrayLength and issue #27346).
+                       if utyp.len < 0 {
+                               utyp.len = n
+                               // e.Type is missing if we have a composite literal element
+                               // that is itself a composite literal with omitted type. In
+                               // that case there is nothing to record (there is no type in
+                               // the source at that point).
+                               if e.Type != nil {
+                                       check.recordTypeAndValue(e.Type, typexpr, utyp, nil)
+                               }
+                       }
+
+               case *Slice:
+                       // Prevent crash if the slice referred to is not yet set up.
+                       // See analogous comment for *Array.
+                       if utyp.elem == nil {
+                               check.error(e, "illegal cycle in type declaration")
+                               goto Error
+                       }
+                       check.indexedElts(e.ElemList, utyp.elem, -1)
+
+               case *Map:
+                       // Prevent crash if the map referred to is not yet set up.
+                       // See analogous comment for *Array.
+                       if utyp.key == nil || utyp.elem == nil {
+                               check.error(e, "illegal cycle in type declaration")
+                               goto Error
+                       }
+                       visited := make(map[interface{}][]Type, len(e.ElemList))
+                       for _, e := range e.ElemList {
+                               kv, _ := e.(*syntax.KeyValueExpr)
+                               if kv == nil {
+                                       check.error(e, "missing key in map literal")
+                                       continue
+                               }
+                               check.exprWithHint(x, kv.Key, utyp.key)
+                               check.assignment(x, utyp.key, "map literal")
+                               if x.mode == invalid {
+                                       continue
+                               }
+                               if x.mode == constant_ {
+                                       duplicate := false
+                                       // if the key is of interface type, the type is also significant when checking for duplicates
+                                       xkey := keyVal(x.val)
+                                       if utyp.key.Interface() != nil {
+                                               for _, vtyp := range visited[xkey] {
+                                                       if check.identical(vtyp, x.typ) {
+                                                               duplicate = true
+                                                               break
+                                                       }
+                                               }
+                                               visited[xkey] = append(visited[xkey], x.typ)
+                                       } else {
+                                               _, duplicate = visited[xkey]
+                                               visited[xkey] = nil
+                                       }
+                                       if duplicate {
+                                               check.errorf(x, "duplicate key %s in map literal", x.val)
+                                               continue
+                                       }
+                               }
+                               check.exprWithHint(x, kv.Value, utyp.elem)
+                               check.assignment(x, utyp.elem, "map literal")
+                       }
+
+               default:
+                       // when "using" all elements unpack KeyValueExpr
+                       // explicitly because check.use doesn't accept them
+                       for _, e := range e.ElemList {
+                               if kv, _ := e.(*syntax.KeyValueExpr); kv != nil {
+                                       // Ideally, we should also "use" kv.Key but we can't know
+                                       // if it's an externally defined struct key or not. Going
+                                       // forward anyway can lead to other errors. Give up instead.
+                                       e = kv.Value
+                               }
+                               check.use(e)
+                       }
+                       // if utyp is invalid, an error was reported before
+                       if utyp != Typ[Invalid] {
+                               check.errorf(e, "invalid composite literal type %s", typ)
+                               goto Error
+                       }
+               }
+
+               x.mode = value
+               x.typ = typ
+
+       case *syntax.ParenExpr:
+               kind := check.rawExpr(x, e.X, nil)
+               x.expr = e
+               return kind
+
+       case *syntax.SelectorExpr:
+               check.selector(x, e)
+
+       case *syntax.IndexExpr:
+               check.exprOrType(x, e.X)
+               if x.mode == invalid {
+                       check.use(e.Index)
+                       goto Error
+               }
+
+               if x.mode == typexpr {
+                       // type instantiation
+                       x.mode = invalid
+                       x.typ = check.varType(e)
+                       if x.typ != Typ[Invalid] {
+                               x.mode = typexpr
+                       }
+                       return expression
+               }
+
+               if x.mode == value {
+                       if sig := x.typ.Signature(); sig != nil && len(sig.tparams) > 0 {
+                               // function instantiation
+                               check.funcInst(x, e)
+                               return expression
+                       }
+               }
+
+               // ordinary index expression
+               valid := false
+               length := int64(-1) // valid if >= 0
+               switch typ := optype(x.typ.Under()).(type) {
+               case *Basic:
+                       if isString(typ) {
+                               valid = true
+                               if x.mode == constant_ {
+                                       length = int64(len(constant.StringVal(x.val)))
+                               }
+                               // an indexed string always yields a byte value
+                               // (not a constant) even if the string and the
+                               // index are constant
+                               x.mode = value
+                               x.typ = universeByte // use 'byte' name
+                       }
+
+               case *Array:
+                       valid = true
+                       length = typ.len
+                       if x.mode != variable {
+                               x.mode = value
+                       }
+                       x.typ = typ.elem
+
+               case *Pointer:
+                       if typ := typ.base.Array(); typ != nil {
+                               valid = true
+                               length = typ.len
+                               x.mode = variable
+                               x.typ = typ.elem
+                       }
+
+               case *Slice:
+                       valid = true
+                       x.mode = variable
+                       x.typ = typ.elem
+
+               case *Map:
+                       var key operand
+                       check.expr(&key, e.Index)
+                       check.assignment(&key, typ.key, "map index")
+                       // ok to continue even if indexing failed - map element type is known
+                       x.mode = mapindex
+                       x.typ = typ.elem
+                       x.expr = e
+                       return expression
+
+               case *Sum:
+                       // A sum type can be indexed if all of the sum's types
+                       // support indexing and have the same index and element
+                       // type. Special rules apply for maps in the sum type.
+                       var tkey, telem Type // key is for map types only
+                       nmaps := 0           // number of map types in sum type
+                       if typ.is(func(t Type) bool {
+                               var e Type
+                               switch t := t.Under().(type) {
+                               case *Basic:
+                                       if isString(t) {
+                                               e = universeByte
+                                       }
+                               case *Array:
+                                       e = t.elem
+                               case *Pointer:
+                                       if t := t.base.Array(); t != nil {
+                                               e = t.elem
+                                       }
+                               case *Slice:
+                                       e = t.elem
+                               case *Map:
+                                       // If there are multiple maps in the sum type,
+                                       // they must have identical key types.
+                                       // TODO(gri) We may be able to relax this rule
+                                       // but it becomes complicated very quickly.
+                                       if tkey != nil && !Identical(t.key, tkey) {
+                                               return false
+                                       }
+                                       tkey = t.key
+                                       e = t.elem
+                                       nmaps++
+                               case *TypeParam:
+                                       check.errorf(x, "type of %s contains a type parameter - cannot index (implementation restriction)", x)
+                               case *instance:
+                                       panic("unimplemented")
+                               }
+                               if e == nil || telem != nil && !Identical(e, telem) {
+                                       return false
+                               }
+                               telem = e
+                               return true
+                       }) {
+                               // If there are maps, the index expression must be assignable
+                               // to the map key type (as for simple map index expressions).
+                               if nmaps > 0 {
+                                       var key operand
+                                       check.expr(&key, e.Index)
+                                       check.assignment(&key, tkey, "map index")
+                                       // ok to continue even if indexing failed - map element type is known
+
+                                       // If there are only maps, we are done.
+                                       if nmaps == len(typ.types) {
+                                               x.mode = mapindex
+                                               x.typ = telem
+                                               x.expr = e
+                                               return expression
+                                       }
+
+                                       // Otherwise we have mix of maps and other types. For
+                                       // now we require that the map key be an integer type.
+                                       // TODO(gri) This is probably not good enough.
+                                       valid = isInteger(tkey)
+                                       // avoid 2nd indexing error if indexing failed above
+                                       if !valid && key.mode == invalid {
+                                               goto Error
+                                       }
+                                       x.mode = value // map index expressions are not addressable
+                               } else {
+                                       // no maps
+                                       valid = true
+                                       x.mode = variable
+                               }
+                               x.typ = telem
+                       }
+               }
+
+               if !valid {
+                       check.invalidOpf(x, "cannot index %s", x)
+                       goto Error
+               }
+
+               if e.Index == nil {
+                       check.invalidASTf(e, "missing index for %s", x)
+                       goto Error
+               }
+
+               index := e.Index
+               if l, _ := index.(*syntax.ListExpr); l != nil {
+                       if n := len(l.ElemList); n <= 1 {
+                               check.invalidASTf(e, "invalid use of ListExpr for index expression %s with %d indices", e, n)
+                               goto Error
+                       }
+                       // len(l.ElemList) > 1
+                       check.invalidOpf(l.ElemList[1], "more than one index")
+                       index = l.ElemList[0] // continue with first index
+               }
+
+               // In pathological (invalid) cases (e.g.: type T1 [][[]T1{}[0][0]]T0)
+               // the element type may be accessed before it's set. Make sure we have
+               // a valid type.
+               if x.typ == nil {
+                       x.typ = Typ[Invalid]
+               }
+
+               check.index(index, length)
+               // ok to continue
+
+       case *syntax.SliceExpr:
+               check.expr(x, e.X)
+               if x.mode == invalid {
+                       check.use(e.Index[:]...)
+                       goto Error
+               }
+
+               valid := false
+               length := int64(-1) // valid if >= 0
+               switch typ := optype(x.typ.Under()).(type) {
+               case *Basic:
+                       if isString(typ) {
+                               if e.Full {
+                                       check.invalidOpf(x, "3-index slice of string")
+                                       goto Error
+                               }
+                               valid = true
+                               if x.mode == constant_ {
+                                       length = int64(len(constant.StringVal(x.val)))
+                               }
+                               // spec: "For untyped string operands the result
+                               // is a non-constant value of type string."
+                               if typ.kind == UntypedString {
+                                       x.typ = Typ[String]
+                               }
+                       }
+
+               case *Array:
+                       valid = true
+                       length = typ.len
+                       if x.mode != variable {
+                               check.invalidOpf(x, "%s (slice of unaddressable value)", x)
+                               goto Error
+                       }
+                       x.typ = &Slice{elem: typ.elem}
+
+               case *Pointer:
+                       if typ := typ.base.Array(); typ != nil {
+                               valid = true
+                               length = typ.len
+                               x.typ = &Slice{elem: typ.elem}
+                       }
+
+               case *Slice:
+                       valid = true
+                       // x.typ doesn't change
+
+               case *Sum, *TypeParam:
+                       check.errorf(x, "generic slice expressions not yet implemented")
+                       goto Error
+               }
+
+               if !valid {
+                       check.invalidOpf(x, "cannot slice %s", x)
+                       goto Error
+               }
+
+               x.mode = value
+
+               // spec: "Only the first index may be omitted; it defaults to 0."
+               if e.Full && (e.Index[1] == nil || e.Index[2] == nil) {
+                       check.invalidASTf(e, "2nd and 3rd index required in 3-index slice")
+                       goto Error
+               }
+
+               // check indices
+               var ind [3]int64
+               for i, expr := range e.Index {
+                       x := int64(-1)
+                       switch {
+                       case expr != nil:
+                               // The "capacity" is only known statically for strings, arrays,
+                               // and pointers to arrays, and it is the same as the length for
+                               // those types.
+                               max := int64(-1)
+                               if length >= 0 {
+                                       max = length + 1
+                               }
+                               if _, v := check.index(expr, max); v >= 0 {
+                                       x = v
+                               }
+                       case i == 0:
+                               // default is 0 for the first index
+                               x = 0
+                       case length >= 0:
+                               // default is length (== capacity) otherwise
+                               x = length
+                       }
+                       ind[i] = x
+               }
+
+               // constant indices must be in range
+               // (check.index already checks that existing indices >= 0)
+       L:
+               for i, x := range ind[:len(ind)-1] {
+                       if x > 0 {
+                               for _, y := range ind[i+1:] {
+                                       if y >= 0 && x > y {
+                                               check.errorf(e, "invalid slice indices: %d > %d", x, y)
+                                               break L // only report one error, ok to continue
+                                       }
+                               }
+                       }
+               }
+
+       case *syntax.AssertExpr:
+               check.expr(x, e.X)
+               if x.mode == invalid {
+                       goto Error
+               }
+               xtyp, _ := x.typ.Under().(*Interface)
+               if xtyp == nil {
+                       check.errorf(x, "%s is not an interface type", x)
+                       goto Error
+               }
+               check.ordinaryType(x.Pos(), xtyp)
+               // x.(type) expressions are encoded via TypeSwitchGuards
+               if e.Type == nil {
+                       check.invalidASTf(e, "invalid use of AssertExpr")
+                       goto Error
+               }
+               T := check.varType(e.Type)
+               if T == Typ[Invalid] {
+                       goto Error
+               }
+               check.typeAssertion(posFor(x), x, xtyp, T, false)
+               x.mode = commaok
+               x.typ = T
+
+       case *syntax.TypeSwitchGuard:
+               // x.(type) expressions are handled explicitly in type switches
+               check.invalidASTf(e, "use of .(type) outside type switch")
+               goto Error
+
+       case *syntax.CallExpr:
+               return check.call(x, e)
+
+       // case *syntax.UnaryExpr:
+       //      check.expr(x, e.X)
+       //      if x.mode == invalid {
+       //              goto Error
+       //      }
+       //      check.unary(x, e, e.Op)
+       //      if x.mode == invalid {
+       //              goto Error
+       //      }
+       //      if e.Op == token.ARROW {
+       //              x.expr = e
+       //              return statement // receive operations may appear in statement context
+       //      }
+
+       // case *syntax.BinaryExpr:
+       //      check.binary(x, e, e.X, e.Y, e.Op)
+       //      if x.mode == invalid {
+       //              goto Error
+       //      }
+
+       case *syntax.Operation:
+               if e.Y == nil {
+                       // unary expression
+                       if e.Op == syntax.Mul {
+                               // pointer indirection
+                               check.exprOrType(x, e.X)
+                               switch x.mode {
+                               case invalid:
+                                       goto Error
+                               case typexpr:
+                                       x.typ = &Pointer{base: x.typ}
+                               default:
+                                       if typ := x.typ.Pointer(); typ != nil {
+                                               x.mode = variable
+                                               x.typ = typ.base
+                                       } else {
+                                               check.invalidOpf(x, "cannot indirect %s", x)
+                                               goto Error
+                                       }
+                               }
+                               break
+                       }
+
+                       check.expr(x, e.X)
+                       if x.mode == invalid {
+                               goto Error
+                       }
+                       check.unary(x, e, e.Op)
+                       if x.mode == invalid {
+                               goto Error
+                       }
+                       if e.Op == syntax.Recv {
+                               x.expr = e
+                               return statement // receive operations may appear in statement context
+                       }
+                       break
+               }
+
+               // binary expression
+               check.binary(x, e, e.X, e.Y, e.Op, e.Y.Pos()) // TODO(gri) should have OpPos here (like in go/types)
+               if x.mode == invalid {
+                       goto Error
+               }
+
+       case *syntax.KeyValueExpr:
+               // key:value expressions are handled in composite literals
+               check.invalidASTf(e, "no key:value expected")
+               goto Error
+
+       case *syntax.ArrayType, *syntax.SliceType, *syntax.StructType, *syntax.FuncType,
+               *syntax.InterfaceType, *syntax.MapType, *syntax.ChanType:
+               x.mode = typexpr
+               x.typ = check.typ(e)
+               // Note: rawExpr (caller of exprInternal) will call check.recordTypeAndValue
+               // even though check.typ has already called it. This is fine as both
+               // times the same expression and type are recorded. It is also not a
+               // performance issue because we only reach here for composite literal
+               // types, which are comparatively rare.
+
+       default:
+               panic(fmt.Sprintf("%s: unknown expression type %T", posFor(e), e))
+       }
+
+       // everything went well
+       x.expr = e
+       return expression
+
+Error:
+       x.mode = invalid
+       x.expr = e
+       return statement // avoid follow-up errors
+}
+
+func keyVal(x constant.Value) interface{} {
+       switch x.Kind() {
+       case constant.Bool:
+               return constant.BoolVal(x)
+       case constant.String:
+               return constant.StringVal(x)
+       case constant.Int:
+               if v, ok := constant.Int64Val(x); ok {
+                       return v
+               }
+               if v, ok := constant.Uint64Val(x); ok {
+                       return v
+               }
+       case constant.Float:
+               v, _ := constant.Float64Val(x)
+               return v
+       case constant.Complex:
+               r, _ := constant.Float64Val(constant.Real(x))
+               i, _ := constant.Float64Val(constant.Imag(x))
+               return complex(r, i)
+       }
+       return x
+}
+
+// typeAssertion checks that x.(T) is legal; xtyp must be the type of x.
+func (check *Checker) typeAssertion(pos syntax.Pos, x *operand, xtyp *Interface, T Type, strict bool) {
+       method, wrongType := check.assertableTo(xtyp, T, strict)
+       if method == nil {
+               return
+       }
+       var msg string
+       if wrongType != nil {
+               if check.identical(method.typ, wrongType.typ) {
+                       msg = fmt.Sprintf("missing method %s (%s has pointer receiver)", method.name, method.name)
+               } else {
+                       msg = fmt.Sprintf("wrong type for method %s (have %s, want %s)", method.name, wrongType.typ, method.typ)
+               }
+       } else {
+               msg = "missing method " + method.name
+       }
+       if check.conf.CompilerErrorMessages {
+               check.errorf(pos, "impossible type assertion: %s (%s)", x, msg)
+       } else {
+               check.errorf(pos, "%s cannot have dynamic type %s (%s)", x, T, msg)
+       }
+}
+
+// expr typechecks expression e and initializes x with the expression value.
+// The result must be a single value.
+// If an error occurred, x.mode is set to invalid.
+//
+func (check *Checker) expr(x *operand, e syntax.Expr) {
+       check.rawExpr(x, e, nil)
+       check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
+       check.singleValue(x)
+}
+
+// multiExpr is like expr but the result may also be a multi-value.
+func (check *Checker) multiExpr(x *operand, e syntax.Expr) {
+       check.rawExpr(x, e, nil)
+       check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
+}
+
+// multiExprOrType is like multiExpr but the result may also be a type.
+func (check *Checker) multiExprOrType(x *operand, e syntax.Expr) {
+       check.rawExpr(x, e, nil)
+       check.exclude(x, 1<<novalue|1<<builtin)
+}
+
+// exprWithHint typechecks expression e and initializes x with the expression value;
+// hint is the type of a composite literal element.
+// If an error occurred, x.mode is set to invalid.
+//
+func (check *Checker) exprWithHint(x *operand, e syntax.Expr, hint Type) {
+       assert(hint != nil)
+       check.rawExpr(x, e, hint)
+       check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
+       check.singleValue(x)
+}
+
+// exprOrType typechecks expression or type e and initializes x with the expression value or type.
+// If an error occurred, x.mode is set to invalid.
+//
+func (check *Checker) exprOrType(x *operand, e syntax.Expr) {
+       check.rawExpr(x, e, nil)
+       check.exclude(x, 1<<novalue)
+       check.singleValue(x)
+}
+
+// exclude reports an error if x.mode is in modeset and sets x.mode to invalid.
+// The modeset may contain any of 1<<novalue, 1<<builtin, 1<<typexpr.
+func (check *Checker) exclude(x *operand, modeset uint) {
+       if modeset&(1<<x.mode) != 0 {
+               var msg string
+               switch x.mode {
+               case novalue:
+                       if modeset&(1<<typexpr) != 0 {
+                               msg = "%s used as value"
+                       } else {
+                               msg = "%s used as value or type"
+                       }
+               case builtin:
+                       msg = "%s must be called"
+               case typexpr:
+                       msg = "%s is not an expression"
+               default:
+                       unreachable()
+               }
+               check.errorf(x, msg, x)
+               x.mode = invalid
+       }
+}
+
+// singleValue reports an error if x describes a tuple and sets x.mode to invalid.
+func (check *Checker) singleValue(x *operand) {
+       if x.mode == value {
+               // tuple types are never named - no need for underlying type below
+               if t, ok := x.typ.(*Tuple); ok {
+                       assert(t.Len() != 1)
+                       check.errorf(x, "%d-valued %s where single value is expected", t.Len(), x)
+                       x.mode = invalid
+               }
+       }
+}
diff --git a/src/cmd/compile/internal/types2/exprstring.go b/src/cmd/compile/internal/types2/exprstring.go
new file mode 100644 (file)
index 0000000..0ec5d13
--- /dev/null
@@ -0,0 +1,293 @@
+// UNREVIEWED
+// Copyright 2013 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.
+
+// This file implements printing of expressions.
+
+package types2
+
+import (
+       "bytes"
+       "cmd/compile/internal/syntax"
+)
+
+// ExprString returns the (possibly shortened) string representation for x.
+// Shortened representations are suitable for user interfaces but may not
+// necessarily follow Go syntax.
+func ExprString(x syntax.Expr) string {
+       var buf bytes.Buffer
+       WriteExpr(&buf, x)
+       return buf.String()
+}
+
+// WriteExpr writes the (possibly shortened) string representation for x to buf.
+// Shortened representations are suitable for user interfaces but may not
+// necessarily follow Go syntax.
+func WriteExpr(buf *bytes.Buffer, x syntax.Expr) {
+       // The AST preserves source-level parentheses so there is
+       // no need to introduce them here to correct for different
+       // operator precedences. (This assumes that the AST was
+       // generated by a Go parser.)
+
+       // TODO(gri): This assumption is not correct - we need to recreate
+       //            parentheses in expressions.
+
+       switch x := x.(type) {
+       default:
+               buf.WriteString("(ast: bad expr)") // nil, syntax.BadExpr, syntax.KeyValueExpr
+
+       case *syntax.Name:
+               buf.WriteString(x.Value)
+
+       case *syntax.DotsType:
+               buf.WriteString("...")
+               if x.Elem != nil {
+                       WriteExpr(buf, x.Elem)
+               }
+
+       case *syntax.BasicLit:
+               buf.WriteString(x.Value)
+
+       case *syntax.FuncLit:
+               WriteExpr(buf, x.Type)
+               if x.Body != nil && len(x.Body.List) > 0 {
+                       buf.WriteString(" {…}") // shortened
+               } else {
+                       buf.WriteString(" {}")
+               }
+
+       case *syntax.CompositeLit:
+               WriteExpr(buf, x.Type)
+               if len(x.ElemList) > 0 {
+                       buf.WriteString("{…}") // shortened
+               } else {
+                       buf.WriteString("{}")
+               }
+
+       case *syntax.ParenExpr:
+               buf.WriteByte('(')
+               WriteExpr(buf, x.X)
+               buf.WriteByte(')')
+
+       case *syntax.SelectorExpr:
+               WriteExpr(buf, x.X)
+               buf.WriteByte('.')
+               buf.WriteString(x.Sel.Value)
+
+       case *syntax.IndexExpr:
+               WriteExpr(buf, x.X)
+               buf.WriteByte('[')
+               WriteExpr(buf, x.Index) // x.Index may be a *ListExpr
+               buf.WriteByte(']')
+
+       case *syntax.SliceExpr:
+               WriteExpr(buf, x.X)
+               buf.WriteByte('[')
+               if x.Index[0] != nil {
+                       WriteExpr(buf, x.Index[0])
+               }
+               buf.WriteByte(':')
+               if x.Index[1] != nil {
+                       WriteExpr(buf, x.Index[1])
+               }
+               if x.Full {
+                       buf.WriteByte(':')
+                       if x.Index[2] != nil {
+                               WriteExpr(buf, x.Index[2])
+                       }
+               }
+               buf.WriteByte(']')
+
+       case *syntax.AssertExpr:
+               WriteExpr(buf, x.X)
+               buf.WriteString(".(")
+               WriteExpr(buf, x.Type)
+               buf.WriteByte(')')
+
+       case *syntax.CallExpr:
+               WriteExpr(buf, x.Fun)
+               buf.WriteByte('(')
+               writeExprList(buf, x.ArgList)
+               if x.HasDots {
+                       buf.WriteString("...")
+               }
+               buf.WriteByte(')')
+
+       case *syntax.ListExpr:
+               writeExprList(buf, x.ElemList)
+
+       case *syntax.Operation:
+               // TODO(gri) This would be simpler if x.X == nil meant unary expression.
+               if x.Y == nil {
+                       // unary expression
+                       buf.WriteString(x.Op.String())
+                       WriteExpr(buf, x.X)
+               } else {
+                       // binary expression
+                       WriteExpr(buf, x.X)
+                       buf.WriteByte(' ')
+                       buf.WriteString(x.Op.String())
+                       buf.WriteByte(' ')
+                       WriteExpr(buf, x.Y)
+               }
+
+               // case *ast.StarExpr:
+               //      buf.WriteByte('*')
+               //      WriteExpr(buf, x.X)
+
+               // case *ast.UnaryExpr:
+               //      buf.WriteString(x.Op.String())
+               //      WriteExpr(buf, x.X)
+
+               // case *ast.BinaryExpr:
+               //      WriteExpr(buf, x.X)
+               //      buf.WriteByte(' ')
+               //      buf.WriteString(x.Op.String())
+               //      buf.WriteByte(' ')
+               //      WriteExpr(buf, x.Y)
+
+       case *syntax.ArrayType:
+               if x.Len == nil {
+                       buf.WriteString("[...]")
+               } else {
+                       buf.WriteByte('[')
+                       WriteExpr(buf, x.Len)
+                       buf.WriteByte(']')
+               }
+               WriteExpr(buf, x.Elem)
+
+       case *syntax.SliceType:
+               buf.WriteString("[]")
+               WriteExpr(buf, x.Elem)
+
+       case *syntax.StructType:
+               buf.WriteString("struct{")
+               writeFieldList(buf, x.FieldList, "; ", false)
+               buf.WriteByte('}')
+
+       case *syntax.FuncType:
+               buf.WriteString("func")
+               writeSigExpr(buf, x)
+
+       case *syntax.InterfaceType:
+               // separate type list types from method list
+               // TODO(gri) we can get rid of this extra code if writeExprList does the separation
+               var types []syntax.Expr
+               var methods []*syntax.Field
+               for _, f := range x.MethodList {
+                       if f.Name != nil && f.Name.Value == "type" {
+                               // type list type
+                               types = append(types, f.Type)
+                       } else {
+                               // method or embedded interface
+                               methods = append(methods, f)
+                       }
+               }
+
+               buf.WriteString("interface{")
+               writeFieldList(buf, methods, "; ", true)
+               if len(types) > 0 {
+                       if len(methods) > 0 {
+                               buf.WriteString("; ")
+                       }
+                       buf.WriteString("type ")
+                       writeExprList(buf, types)
+               }
+               buf.WriteByte('}')
+
+       case *syntax.MapType:
+               buf.WriteString("map[")
+               WriteExpr(buf, x.Key)
+               buf.WriteByte(']')
+               WriteExpr(buf, x.Value)
+
+       case *syntax.ChanType:
+               var s string
+               switch x.Dir {
+               case syntax.SendOnly:
+                       s = "chan<- "
+               case syntax.RecvOnly:
+                       s = "<-chan "
+               default:
+                       s = "chan "
+               }
+               buf.WriteString(s)
+               if e, _ := x.Elem.(*syntax.ChanType); x.Dir != syntax.SendOnly && e != nil && e.Dir == syntax.RecvOnly {
+                       // don't print chan (<-chan T) as chan <-chan T (but chan<- <-chan T is ok)
+                       buf.WriteByte('(')
+                       WriteExpr(buf, x.Elem)
+                       buf.WriteByte(')')
+               } else {
+                       WriteExpr(buf, x.Elem)
+               }
+       }
+}
+
+func writeSigExpr(buf *bytes.Buffer, sig *syntax.FuncType) {
+       buf.WriteByte('(')
+       writeFieldList(buf, sig.ParamList, ", ", false)
+       buf.WriteByte(')')
+
+       res := sig.ResultList
+       n := len(res)
+       if n == 0 {
+               // no result
+               return
+       }
+
+       buf.WriteByte(' ')
+       if n == 1 && res[0].Name == nil {
+               // single unnamed result
+               WriteExpr(buf, res[0].Type)
+               return
+       }
+
+       // multiple or named result(s)
+       buf.WriteByte('(')
+       writeFieldList(buf, res, ", ", false)
+       buf.WriteByte(')')
+}
+
+func writeFieldList(buf *bytes.Buffer, list []*syntax.Field, sep string, iface bool) {
+       for i := 0; i < len(list); {
+               f := list[i]
+               if i > 0 {
+                       buf.WriteString(sep)
+               }
+
+               // if we don't have a name, we have an embedded type
+               if f.Name == nil {
+                       WriteExpr(buf, f.Type)
+                       i++
+                       continue
+               }
+
+               // types of interface methods consist of signatures only
+               if sig, _ := f.Type.(*syntax.FuncType); sig != nil && iface {
+                       buf.WriteString(f.Name.Value)
+                       writeSigExpr(buf, sig)
+                       i++
+                       continue
+               }
+
+               // write the type only once for a sequence of fields with the same type
+               t := f.Type
+               buf.WriteString(f.Name.Value)
+               for i++; i < len(list) && list[i].Type == t; i++ {
+                       buf.WriteString(", ")
+                       buf.WriteString(list[i].Name.Value)
+               }
+               buf.WriteByte(' ')
+               WriteExpr(buf, t)
+       }
+}
+
+func writeExprList(buf *bytes.Buffer, list []syntax.Expr) {
+       for i, x := range list {
+               if i > 0 {
+                       buf.WriteString(", ")
+               }
+               WriteExpr(buf, x)
+       }
+}
diff --git a/src/cmd/compile/internal/types2/exprstring_test.go b/src/cmd/compile/internal/types2/exprstring_test.go
new file mode 100644 (file)
index 0000000..efb7c30
--- /dev/null
@@ -0,0 +1,97 @@
+// UNREVIEWED
+// Copyright 2013 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 (
+       "testing"
+
+       "cmd/compile/internal/syntax"
+       . "cmd/compile/internal/types2"
+)
+
+var testExprs = []testEntry{
+       // basic type literals
+       dup("x"),
+       dup("true"),
+       dup("42"),
+       dup("3.1415"),
+       dup("2.71828i"),
+       dup(`'a'`),
+       dup(`"foo"`),
+       dup("`bar`"),
+
+       // func and composite literals
+       {"func(){}", "func() {}"},
+       {"func(x int) complex128 {}", "func(x int) complex128 {}"},
+       {"[]int{1, 2, 3}", "[]int{…}"},
+
+       // non-type expressions
+       dup("(x)"),
+       dup("x.f"),
+       dup("a[i]"),
+
+       dup("s[:]"),
+       dup("s[i:]"),
+       dup("s[:j]"),
+       dup("s[i:j]"),
+       dup("s[:j:k]"),
+       dup("s[i:j:k]"),
+
+       dup("x.(T)"),
+
+       dup("x.([10]int)"),
+       dup("x.([...]int)"),
+
+       dup("x.(struct{})"),
+       dup("x.(struct{x int; y, z float32; E})"),
+
+       dup("x.(func())"),
+       dup("x.(func(x int))"),
+       dup("x.(func() int)"),
+       dup("x.(func(x, y int, z float32) (r int))"),
+       dup("x.(func(a, b, c int))"),
+       dup("x.(func(x ...T))"),
+
+       dup("x.(interface{})"),
+       dup("x.(interface{m(); n(x int); E})"),
+       dup("x.(interface{m(); n(x int) T; E; F})"),
+
+       dup("x.(map[K]V)"),
+
+       dup("x.(chan E)"),
+       dup("x.(<-chan E)"),
+       dup("x.(chan<- chan int)"),
+       dup("x.(chan<- <-chan int)"),
+       dup("x.(<-chan chan int)"),
+       dup("x.(chan (<-chan int))"),
+
+       dup("f()"),
+       dup("f(x)"),
+       dup("int(x)"),
+       dup("f(x, x + y)"),
+       dup("f(s...)"),
+       dup("f(a, s...)"),
+
+       dup("*x"),
+       dup("&x"),
+       dup("x + y"),
+       dup("x + y << (2 * s)"),
+}
+
+func TestExprString(t *testing.T) {
+       for _, test := range testExprs {
+               src := "package p; var _ = " + test.src
+               f, err := parseSrc("expr", src)
+               if err != nil {
+                       t.Errorf("%s: %s", test.src, err)
+                       continue
+               }
+               x := f.DeclList[0].(*syntax.VarDecl).Values
+               if got := ExprString(x); got != test.str {
+                       t.Errorf("%s: got %s, want %s", test.src, got, test.str)
+               }
+       }
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue20583.src b/src/cmd/compile/internal/types2/fixedbugs/issue20583.src
new file mode 100644 (file)
index 0000000..efc1ace
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2020 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 issue20583
+const (
+       _ = 6e886451608 /* ERROR malformed constant */ /2
+       _ = 6e886451608i /* ERROR malformed constant */ /2
+       _ = 0 * 1e+1000000000 // ERROR malformed constant
+       x = 1e100000000
+       _ = x*x*x*x*x*x*x /* ERROR not representable */ // TODO(gri) this error should be at the last *
+)
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39634.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39634.go2
new file mode 100644 (file)
index 0000000..f37930d
--- /dev/null
@@ -0,0 +1,92 @@
+// UNREVIEWED
+// Copyright 2020 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.
+
+// Examples adjusted to match new [T any] syntax for type parameters.
+// Also, previously permitted empty type parameter lists and instantiations
+// are now syntax errors.
+
+package p
+
+// crash 1
+type nt1[_ any]interface{g /* ERROR undeclared name */ }
+type ph1[e nt1[e],g(d /* ERROR undeclared name */ )]s /* ERROR undeclared name */
+func(*ph1[e,e /* ERROR redeclared */ ])h(d /* ERROR undeclared name */ )
+
+// crash 2
+// Disabled: empty []'s are now syntax errors. This example leads to too many follow-on errors.
+// type Numeric2 interface{t2 /* ERROR not a type */ }
+// func t2[T Numeric2](s[]T){0 /* ERROR not a type */ []{s /* ERROR cannot index */ [0][0]}}
+
+// crash 3
+type t3 *interface{ t3.p /* ERROR no field or method p */ }
+
+// crash 4
+type Numeric4 interface{t4 /* ERROR not a type */ }
+func t4[T Numeric4](s[]T){if( /* ERROR non-boolean */ 0){*s /* ERROR cannot indirect */ [0]}}
+
+// crash 7
+type foo7 interface { bar() }
+type x7[A any] struct{ foo7 }
+func main7() { var _ foo7 = x7[int]{} }
+
+// crash 8
+type foo8[A any] interface { type A }
+func bar8[A foo8[A]](a A) {}
+func main8() {}
+
+// crash 9
+type foo9[A any] interface { type foo9 /* ERROR interface contains type constraints */ [A] }
+func _() { var _ = new(foo9 /* ERROR interface contains type constraints */ [int]) }
+
+// crash 12
+var u /* ERROR cycle */ , i [func /* ERROR used as value */ /* ERROR used as value */ (u, c /* ERROR undeclared */ /* ERROR undeclared */ ) {}(0, len)]c /* ERROR undeclared */ /* ERROR undeclared */
+
+// crash 15
+func y15() { var a /* ERROR declared but not used */ interface{ p() } = G15[string]{} }
+type G15[X any] s /* ERROR undeclared name */
+func (G15 /* ERROR generic type .* without instantiation */ ) p()
+
+// crash 16
+type Foo16[T any] r16 /* ERROR not a type */
+func r16[T any]() Foo16[Foo16[T]]
+
+// crash 17
+type Y17 interface{ c() }
+type Z17 interface {
+       c() Y17
+       Y17 /* ERROR duplicate method */
+}
+func F17[T Z17](T)
+
+// crash 18
+type o18[T any] []func(_ o18[[]_ /* ERROR cannot use _ */ ])
+
+// crash 19
+type Z19 [][[]Z19{}[0][0]]c19 /* ERROR undeclared */
+
+// crash 20
+type Z20 /* ERROR illegal cycle */ interface{ Z20 }
+func F20[t Z20]() { F20(t /* ERROR invalid composite literal type */ {}) }
+
+// crash 21
+type Z21 /* ERROR illegal cycle */ interface{ Z21 }
+func F21[T Z21]() { ( /* ERROR not used */ F21[Z21]) }
+
+// crash 24
+type T24[P any] P
+func (r T24[P]) m() { T24 /* ERROR without instantiation */ .m() }
+
+// crash 25
+type T25[A any] int
+func (t T25[A]) m1() {}
+var x T25 /* ERROR without instantiation */ .m1
+
+// crash 26
+type T26 = interface{ F26[ /* ERROR cannot have type parameters */ Z any]() }
+func F26[Z any]() T26 { return F26 /* ERROR without instantiation */ /* ERROR missing method */ [] /* ERROR operand */ }
+
+// crash 27
+func e27[T any]() interface{ x27 /* ERROR not a type */ }
+func x27() { e27( /* ERROR cannot infer T */ ) }
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39664.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39664.go2
new file mode 100644 (file)
index 0000000..cf566c3
--- /dev/null
@@ -0,0 +1,16 @@
+// UNREVIEWED
+// Copyright 2020 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 T[_ any] struct {}
+
+func (T /* ERROR instantiation */ ) m()
+
+func _() {
+       var x interface { m() }
+       x = T[int]{}
+       _ = x
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39680.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39680.go2
new file mode 100644 (file)
index 0000000..3239c57
--- /dev/null
@@ -0,0 +1,28 @@
+// UNREVIEWED
+// Copyright 2020 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
+
+import "fmt"
+
+// Minimal test case.
+func _[T interface{type T}](x T) T{
+       return x
+}
+
+// Test case from issue.
+type constr[T any] interface {
+       type T
+}
+
+func Print[T constr[T]](s []T) {
+       for _, v := range s {
+               fmt.Print(v)
+       }
+}
+
+func f() {
+       Print([]string{"Hello, ", "playground\n"})
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39693.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39693.go2
new file mode 100644 (file)
index 0000000..6f4d701
--- /dev/null
@@ -0,0 +1,15 @@
+// UNREVIEWED
+// Copyright 2020 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 Number interface {
+       int     /* ERROR int is not an interface */
+       float64 /* ERROR float64 is not an interface */
+}
+
+func Add[T Number](a, b T) T {
+       return a /* ERROR not defined */ + b
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39699.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39699.go2
new file mode 100644 (file)
index 0000000..c8655ef
--- /dev/null
@@ -0,0 +1,30 @@
+// UNREVIEWED
+// Copyright 2020 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 T0 interface{
+}
+
+type T1 interface{
+       type int
+}
+
+type T2 interface{
+       comparable
+}
+
+type T3 interface {
+       T0
+       T1
+       T2
+}
+
+func _() {
+       _ = T0(0)
+       _ = T1 /* ERROR cannot use interface T1 in conversion */ (1)
+       _ = T2 /* ERROR cannot use interface T2 in conversion */ (2)
+       _ = T3 /* ERROR cannot use interface T3 in conversion */ (3)
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39711.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39711.go2
new file mode 100644 (file)
index 0000000..8edce78
--- /dev/null
@@ -0,0 +1,12 @@
+// UNREVIEWED
+// Copyright 2020 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
+
+// Do not report a duplicate type error for this type list.
+// (Check types after interfaces have been completed.)
+type _ interface {
+       type interface{ Error() string }, interface{ String() string }
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39723.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39723.go2
new file mode 100644 (file)
index 0000000..8a4006e
--- /dev/null
@@ -0,0 +1,10 @@
+// UNREVIEWED
+// Copyright 2020 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
+
+// A constraint must be an interface; it cannot
+// be a type parameter, for instance.
+func _[A interface{ type interface{} }, B A /* ERROR not an interface */ ]()
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39725.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39725.go2
new file mode 100644 (file)
index 0000000..6de661a
--- /dev/null
@@ -0,0 +1,17 @@
+// UNREVIEWED
+// Copyright 2020 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
+
+func f1[T1, T2 any](T1, T2, struct{a T1; b T2})
+func _() {
+       f1(42, string("foo"), struct /* ERROR does not match inferred type struct\{a int; b string\} */ {a, b int}{})
+}
+
+// simplified test case from issue
+func f2[T any](_ []T, _ func(T))
+func _() {
+       f2([]string{}, func /* ERROR does not match inferred type func\(string\) */ (f []byte) {})
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39754.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39754.go2
new file mode 100644 (file)
index 0000000..36b774f
--- /dev/null
@@ -0,0 +1,21 @@
+// UNREVIEWED
+// Copyright 2020 The Go Authors. All rights reserved.\r
+// Use of this source code is governed by a BSD-style\r
+// license that can be found in the LICENSE file.\r
+\r
+package p\r
+\r
+type Optional[T any] struct {}\r
+\r
+func (_ Optional[T]) Val() (T, bool)\r
+\r
+type Box[T any] interface {\r
+       Val() (T, bool)\r
+}\r
+\r
+func f[V interface{}, A, B Box[V]]() {}\r
+\r
+func _() {\r
+       f[int, Optional[int], Optional[int]]()\r
+       f[int, Optional[int], Optional /* ERROR does not satisfy Box */ [string]]()\r
+}\r
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39755.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39755.go2
new file mode 100644 (file)
index 0000000..93aea85
--- /dev/null
@@ -0,0 +1,24 @@
+// UNREVIEWED
+// Copyright 2020 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
+
+func _[T interface{type map[string]int}](x T) {
+       _ = x == nil
+}
+
+// simplified test case from issue
+
+type PathParamsConstraint interface {
+        type map[string]string, []struct{key, value string}
+}
+
+type PathParams[T PathParamsConstraint] struct {
+       t T
+}
+
+func (pp *PathParams[T]) IsNil() bool {
+       return pp.t == nil // this must succeed
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39768.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39768.go2
new file mode 100644 (file)
index 0000000..81b4a91
--- /dev/null
@@ -0,0 +1,21 @@
+// UNREVIEWED
+// Copyright 2020 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 T[P any] P
+type A = T
+var x A[int]
+var _ A /* ERROR cannot use generic type */
+
+type B = T[int]
+var y B = x
+var _ B /* ERROR not a generic type */ [int]
+
+// test case from issue
+
+type Vector[T any] []T
+type VectorAlias = Vector
+var v Vector[int]
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39938.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39938.go2
new file mode 100644 (file)
index 0000000..19e69e6
--- /dev/null
@@ -0,0 +1,51 @@
+// UNREVIEWED
+// Copyright 2020 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.
+
+// Check "infinite expansion" cycle errors across instantiated types.
+
+package p
+
+type E0[P any] P
+type E1[P any] *P
+type E2[P any] struct{ P }
+type E3[P any] struct{ *P }
+
+type T0 /* ERROR illegal cycle */ struct {
+        _ E0[T0]
+}
+
+type T0_ /* ERROR illegal cycle */ struct {
+        E0[T0_]
+}
+
+type T1 struct {
+        _ E1[T1]
+}
+
+type T2 /* ERROR illegal cycle */ struct {
+        _ E2[T2]
+}
+
+type T3 struct {
+        _ E3[T3]
+}
+
+// some more complex cases
+
+type T4 /* ERROR illegal cycle */ struct {
+       _ E0[E2[T4]]
+}
+
+type T5 struct {
+       _ E0[E2[E0[E1[E2[[10]T5]]]]]
+}
+
+type T6 /* ERROR illegal cycle */ struct {
+       _ E0[[10]E2[E0[E2[E2[T6]]]]]
+}
+
+type T7 struct {
+       _ E0[[]E2[E0[E2[E2[T6]]]]]
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39948.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39948.go2
new file mode 100644 (file)
index 0000000..dede9c5
--- /dev/null
@@ -0,0 +1,10 @@
+// UNREVIEWED
+// Copyright 2020 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 T[P any] interface{
+       P // ERROR P is a type parameter, not an interface
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39976.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39976.go2
new file mode 100644 (file)
index 0000000..2ab9664
--- /dev/null
@@ -0,0 +1,17 @@
+// UNREVIEWED
+// Copyright 2020 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 policy[K, V any] interface{}
+type LRU[K, V any] struct{}
+
+func NewCache[K, V any](p policy[K, V])
+
+func _() {
+       var lru LRU[int, string]
+       NewCache[int, string](&lru)
+       NewCache(& /* ERROR does not match policy\[K, V\] \(cannot infer K and V\) */ lru)
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue39982.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue39982.go2
new file mode 100644 (file)
index 0000000..3abdfcb
--- /dev/null
@@ -0,0 +1,37 @@
+// UNREVIEWED
+// Copyright 2020 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 (
+       T[_ any] struct{}
+       S[_ any] struct {
+               data T[*T[int]]
+       }
+)
+
+func _() {
+       _ = S[int]{
+               data: T[*T[int]]{},
+       }
+}
+
+// full test case from issue
+
+type (
+       Element[TElem any] struct{}
+
+       entry[K comparable] struct{}
+
+       Cache[K comparable] struct {
+               data map[K]*Element[*entry[K]]
+       }
+)
+
+func _() {
+       _ = Cache[int]{
+               data: make(map[int](*Element[*entry[int]])),
+       }
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue40038.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue40038.go2
new file mode 100644 (file)
index 0000000..fe3963a
--- /dev/null
@@ -0,0 +1,16 @@
+// UNREVIEWED
+// Copyright 2020 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 A[T any] int
+
+func (A[T]) m(A[T])
+
+func f[P interface{m(P)}]()
+
+func _() {
+       _ = f[A[int]]
+}
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue40056.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue40056.go2
new file mode 100644 (file)
index 0000000..0c78c3f
--- /dev/null
@@ -0,0 +1,16 @@
+// UNREVIEWED
+// Copyright 2020 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
+
+func _() {
+       NewS( /* ERROR cannot infer T */ ) .M()
+}
+
+type S struct {}
+
+func NewS[T any]() *S
+
+func (_ *S /* ERROR S is not a generic type */ [T]) M()
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue40057.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue40057.go2
new file mode 100644 (file)
index 0000000..b2ff11e
--- /dev/null
@@ -0,0 +1,18 @@
+// UNREVIEWED
+// Copyright 2020 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
+
+func _() {
+       var x interface{}
+       switch t := x.(type) {
+       case S /* ERROR cannot use generic type */ :
+               t.m()
+       }
+}
+
+type S[T any] struct {}
+
+func (_ S[T]) m()
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue40301.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue40301.go2
new file mode 100644 (file)
index 0000000..6a3dfc7
--- /dev/null
@@ -0,0 +1,13 @@
+// UNREVIEWED
+// Copyright 2020 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
+
+import "unsafe"
+
+func _[T any](x T) {
+       _ = unsafe /* ERROR undefined */ .Alignof(x)
+       _ = unsafe /* ERROR undefined */ .Sizeof(x)
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue40684.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue40684.go2
new file mode 100644 (file)
index 0000000..001c6d7
--- /dev/null
@@ -0,0 +1,16 @@
+// UNREVIEWED
+// Copyright 2020 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 T[_ any] int
+
+func f[_ any]()
+func g[_, _ any]()
+
+func _() {
+       _ = f[T /* ERROR without instantiation */ ]
+       _ = g[T /* ERROR without instantiation */ , T /* ERROR without instantiation */ ]
+}
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue41124.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue41124.go2
new file mode 100644 (file)
index 0000000..3098f44
--- /dev/null
@@ -0,0 +1,92 @@
+// UNREVIEWED
+// Copyright 2020 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
+
+// Test case from issue.
+
+type Nat interface {
+       type Zero, Succ
+}
+
+type Zero struct{}
+type Succ struct{
+       Nat // ERROR interface contains type constraints
+}
+
+// Struct tests.
+
+type I1 interface {
+       comparable
+}
+
+type I2 interface {
+       type int
+}
+
+type I3 interface {
+       I1
+       I2
+}
+
+type _ struct {
+       f I1 // ERROR interface is .* comparable
+}
+
+type _ struct {
+       comparable // ERROR interface is .* comparable
+}
+
+type _ struct{
+       I1 // ERROR interface is .* comparable
+}
+
+type _ struct{
+       I2 // ERROR interface contains type constraints
+}
+
+type _ struct{
+       I3 // ERROR interface contains type constraints
+}
+
+// General composite types.
+
+type (
+       _ [10]I1 // ERROR interface is .* comparable
+       _ [10]I2 // ERROR interface contains type constraints
+
+       _ []I1 // ERROR interface is .* comparable
+       _ []I2 // ERROR interface contains type constraints
+
+       _ *I3 // ERROR interface contains type constraints
+       _ map[I1 /* ERROR interface is .* comparable */ ]I2 // ERROR interface contains type constraints
+       _ chan I3 // ERROR interface contains type constraints
+       _ func(I1 /* ERROR interface is .* comparable */ )
+       _ func() I2 // ERROR interface contains type constraints
+)
+
+// Other cases.
+
+var _ = [...]I3 /* ERROR interface contains type constraints */ {}
+
+func _(x interface{}) {
+       _ = x.(I3 /* ERROR interface contains type constraints */ )
+}
+
+type T1[_ any] struct{}
+type T3[_, _, _ any] struct{}
+var _ T1[I2 /* ERROR interface contains type constraints */ ]
+var _ T3[int, I2 /* ERROR interface contains type constraints */ , float32]
+
+func f1[_ any]() int
+var _ = f1[I2 /* ERROR interface contains type constraints */ ]()
+func f3[_, _, _ any]() int
+var _ = f3[int, I2 /* ERROR interface contains type constraints */ , float32]()
+
+func _(x interface{}) {
+       switch x.(type) {
+       case I2 /* ERROR interface contains type constraints */ :
+       }
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue42695.src b/src/cmd/compile/internal/types2/fixedbugs/issue42695.src
new file mode 100644 (file)
index 0000000..d0d6200
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2020 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 issue42695
+
+const _ = 6e5518446744 // ERROR malformed constant
+const _ uint8 = 6e5518446744 // ERROR malformed constant
+
+var _ = 6e5518446744 // ERROR malformed constant
+var _ uint8 = 6e5518446744 // ERROR malformed constant
+
+func f(x int) int {
+        return x + 6e5518446744 // ERROR malformed constant
+}
+
+var _ = f(6e5518446744 /* ERROR malformed constant */ )
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue42758.go2 b/src/cmd/compile/internal/types2/fixedbugs/issue42758.go2
new file mode 100644 (file)
index 0000000..698cb8a
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2020 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
+
+func _[T any](x interface{}){
+       switch x.(type) {
+       case T: // ok to use a type parameter
+       case int:
+       }
+
+       switch x.(type) {
+       case T:
+       case T /* ERROR duplicate case */ :
+       }
+}
+
+type constraint interface {
+       type int
+}
+
+func _[T constraint](x interface{}){
+       switch x.(type) {
+       case T: // ok to use a type parameter even if type list contains int
+       case int:
+       }
+}
+
+func _(x constraint /* ERROR contains type constraints */ ) {
+       switch x /* ERROR contains type constraints */ .(type) {
+       }
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue43110.src b/src/cmd/compile/internal/types2/fixedbugs/issue43110.src
new file mode 100644 (file)
index 0000000..4a46945
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2020 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 P *struct{}
+
+func _() {
+       // want an error even if the switch is empty
+       var a struct{ _ func() }
+       switch a /* ERROR cannot switch on a */ {
+       }
+
+       switch a /* ERROR cannot switch on a */ {
+       case a: // no follow-on error here
+       }
+
+       // this is ok because f can be compared to nil
+       var f func()
+       switch f {
+       }
+
+       switch f {
+       case nil:
+       }
+
+       switch (func())(nil) {
+       case nil:
+       }
+
+       switch (func())(nil) {
+       case f /* ERROR cannot compare */ :
+       }
+
+       switch nil /* ERROR use of untyped nil in switch expression */ {
+       }
+
+       // this is ok
+       switch P(nil) {
+       case P(nil):
+       }
+}
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue43124.src b/src/cmd/compile/internal/types2/fixedbugs/issue43124.src
new file mode 100644 (file)
index 0000000..7e48c22
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2020 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 _ = int(0 /* ERROR invalid use of \.\.\. in type conversion */ ...)
+
+// test case from issue
+
+type M []string
+
+var (
+       x = []string{"a", "b"}
+       _ = M(x /* ERROR invalid use of \.\.\. in type conversion */ ...)
+)
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue43125.src b/src/cmd/compile/internal/types2/fixedbugs/issue43125.src
new file mode 100644 (file)
index 0000000..c2bd970
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2020 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 _ = new(- /* ERROR not a type */ 1)
+var _ = new(1 /* ERROR not a type */ + 1)
diff --git a/src/cmd/compile/internal/types2/fixedbugs/issue43190.src b/src/cmd/compile/internal/types2/fixedbugs/issue43190.src
new file mode 100644 (file)
index 0000000..ae42719
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2020 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
+
+import ; // ERROR missing import path
+import
+var /* ERROR missing import path */ _ int
+import .; // ERROR missing import path
+
+import ()
+import (.) // ERROR missing import path
+import (
+       "fmt"
+       .
+) // ERROR missing import path
+
+var _ = fmt.Println // avoid imported but not used error
diff --git a/src/cmd/compile/internal/types2/gccgosizes.go b/src/cmd/compile/internal/types2/gccgosizes.go
new file mode 100644 (file)
index 0000000..05aba53
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2019 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.
+
+// This is a copy of the file generated during the gccgo build process.
+// Last update 2019-01-22.
+
+package types2
+
+var gccgoArchSizes = map[string]*StdSizes{
+       "386":         {4, 4},
+       "alpha":       {8, 8},
+       "amd64":       {8, 8},
+       "amd64p32":    {4, 8},
+       "arm":         {4, 8},
+       "armbe":       {4, 8},
+       "arm64":       {8, 8},
+       "arm64be":     {8, 8},
+       "ia64":        {8, 8},
+       "m68k":        {4, 2},
+       "mips":        {4, 8},
+       "mipsle":      {4, 8},
+       "mips64":      {8, 8},
+       "mips64le":    {8, 8},
+       "mips64p32":   {4, 8},
+       "mips64p32le": {4, 8},
+       "nios2":       {4, 8},
+       "ppc":         {4, 8},
+       "ppc64":       {8, 8},
+       "ppc64le":     {8, 8},
+       "riscv":       {4, 8},
+       "riscv64":     {8, 8},
+       "s390":        {4, 8},
+       "s390x":       {8, 8},
+       "sh":          {4, 8},
+       "shbe":        {4, 8},
+       "sparc":       {4, 8},
+       "sparc64":     {8, 8},
+       "wasm":        {8, 8},
+}
diff --git a/src/cmd/compile/internal/types2/hilbert_test.go b/src/cmd/compile/internal/types2/hilbert_test.go
new file mode 100644 (file)
index 0000000..9f9dad6
--- /dev/null
@@ -0,0 +1,219 @@
+// Copyright 2013 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 (
+       "bytes"
+       "cmd/compile/internal/syntax"
+       "flag"
+       "fmt"
+       "io/ioutil"
+       "testing"
+
+       . "cmd/compile/internal/types2"
+)
+
+var (
+       H   = flag.Int("H", 5, "Hilbert matrix size")
+       out = flag.String("out", "", "write generated program to out")
+)
+
+func TestHilbert(t *testing.T) {
+       // generate source
+       src := program(*H, *out)
+       if *out != "" {
+               ioutil.WriteFile(*out, src, 0666)
+               return
+       }
+
+       // parse source
+       // TODO(gri) get rid of []bytes to string conversion below
+       f, err := parseSrc("hilbert.go", string(src))
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // type-check file
+       DefPredeclaredTestFuncs() // define assert built-in
+       conf := Config{Importer: defaultImporter()}
+       _, err = conf.Check(f.PkgName.Value, []*syntax.File{f}, nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+}
+
+func program(n int, out string) []byte {
+       var g gen
+
+       g.p(`// Code generated by: go test -run=Hilbert -H=%d -out=%q. DO NOT EDIT.
+
+// +`+`build ignore
+
+// This program tests arbitrary precision constant arithmetic
+// by generating the constant elements of a Hilbert matrix H,
+// its inverse I, and the product P = H*I. The product should
+// be the identity matrix.
+package main
+
+func main() {
+       if !ok {
+               printProduct()
+               return
+       }
+       println("PASS")
+}
+
+`, n, out)
+       g.hilbert(n)
+       g.inverse(n)
+       g.product(n)
+       g.verify(n)
+       g.printProduct(n)
+       g.binomials(2*n - 1)
+       g.factorials(2*n - 1)
+
+       return g.Bytes()
+}
+
+type gen struct {
+       bytes.Buffer
+}
+
+func (g *gen) p(format string, args ...interface{}) {
+       fmt.Fprintf(&g.Buffer, format, args...)
+}
+
+func (g *gen) hilbert(n int) {
+       g.p(`// Hilbert matrix, n = %d
+const (
+`, n)
+       for i := 0; i < n; i++ {
+               g.p("\t")
+               for j := 0; j < n; j++ {
+                       if j > 0 {
+                               g.p(", ")
+                       }
+                       g.p("h%d_%d", i, j)
+               }
+               if i == 0 {
+                       g.p(" = ")
+                       for j := 0; j < n; j++ {
+                               if j > 0 {
+                                       g.p(", ")
+                               }
+                               g.p("1.0/(iota + %d)", j+1)
+                       }
+               }
+               g.p("\n")
+       }
+       g.p(")\n\n")
+}
+
+func (g *gen) inverse(n int) {
+       g.p(`// Inverse Hilbert matrix
+const (
+`)
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       s := "+"
+                       if (i+j)&1 != 0 {
+                               s = "-"
+                       }
+                       g.p("\ti%d_%d = %s%d * b%d_%d * b%d_%d * b%d_%d * b%d_%d\n",
+                               i, j, s, i+j+1, n+i, n-j-1, n+j, n-i-1, i+j, i, i+j, i)
+               }
+               g.p("\n")
+       }
+       g.p(")\n\n")
+}
+
+func (g *gen) product(n int) {
+       g.p(`// Product matrix
+const (
+`)
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       g.p("\tp%d_%d = ", i, j)
+                       for k := 0; k < n; k++ {
+                               if k > 0 {
+                                       g.p(" + ")
+                               }
+                               g.p("h%d_%d*i%d_%d", i, k, k, j)
+                       }
+                       g.p("\n")
+               }
+               g.p("\n")
+       }
+       g.p(")\n\n")
+}
+
+func (g *gen) verify(n int) {
+       g.p(`// Verify that product is the identity matrix
+const ok =
+`)
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       if j == 0 {
+                               g.p("\t")
+                       } else {
+                               g.p(" && ")
+                       }
+                       v := 0
+                       if i == j {
+                               v = 1
+                       }
+                       g.p("p%d_%d == %d", i, j, v)
+               }
+               g.p(" &&\n")
+       }
+       g.p("\ttrue\n\n")
+
+       // verify ok at type-check time
+       if *out == "" {
+               g.p("const _ = assert(ok)\n\n")
+       }
+}
+
+func (g *gen) printProduct(n int) {
+       g.p("func printProduct() {\n")
+       for i := 0; i < n; i++ {
+               g.p("\tprintln(")
+               for j := 0; j < n; j++ {
+                       if j > 0 {
+                               g.p(", ")
+                       }
+                       g.p("p%d_%d", i, j)
+               }
+               g.p(")\n")
+       }
+       g.p("}\n\n")
+}
+
+func (g *gen) binomials(n int) {
+       g.p(`// Binomials
+const (
+`)
+       for j := 0; j <= n; j++ {
+               if j > 0 {
+                       g.p("\n")
+               }
+               for k := 0; k <= j; k++ {
+                       g.p("\tb%d_%d = f%d / (f%d*f%d)\n", j, k, j, k, j-k)
+               }
+       }
+       g.p(")\n\n")
+}
+
+func (g *gen) factorials(n int) {
+       g.p(`// Factorials
+const (
+       f0 = 1
+       f1 = 1
+`)
+       for i := 2; i <= n; i++ {
+               g.p("\tf%d = f%d * %d\n", i, i-1, i)
+       }
+       g.p(")\n\n")
+}
diff --git a/src/cmd/compile/internal/types2/importer_test.go b/src/cmd/compile/internal/types2/importer_test.go
new file mode 100644 (file)
index 0000000..90476c4
--- /dev/null
@@ -0,0 +1,36 @@
+// UNREVIEWED
+// Copyright 2020 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.
+
+// This file implements the (temporary) plumbing to get importing to work.
+
+package types2_test
+
+import (
+       gcimporter "cmd/compile/internal/importer"
+       "cmd/compile/internal/types2"
+       "io"
+)
+
+func defaultImporter() types2.Importer {
+       return &gcimports{
+               packages: make(map[string]*types2.Package),
+       }
+}
+
+type gcimports struct {
+       packages map[string]*types2.Package
+       lookup   func(path string) (io.ReadCloser, error)
+}
+
+func (m *gcimports) Import(path string) (*types2.Package, error) {
+       return m.ImportFrom(path, "" /* no vendoring */, 0)
+}
+
+func (m *gcimports) ImportFrom(path, srcDir string, mode types2.ImportMode) (*types2.Package, error) {
+       if mode != 0 {
+               panic("mode must be 0")
+       }
+       return gcimporter.Import(m.packages, path, srcDir, m.lookup)
+}
diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go
new file mode 100644 (file)
index 0000000..125d3f3
--- /dev/null
@@ -0,0 +1,360 @@
+// UNREVIEWED
+// Copyright 2018 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.
+
+// This file implements type parameter inference given
+// a list of concrete arguments and a parameter list.
+
+package types2
+
+import "bytes"
+
+// infer returns the list of actual type arguments for the given list of type parameters tparams
+// by inferring them from the actual arguments args for the parameters params. If type inference
+// is impossible because unification fails, an error is reported and the resulting types list is
+// nil, and index is 0. Otherwise, types is the list of inferred type arguments, and index is
+// the index of the first type argument in that list that couldn't be inferred (and thus is nil).
+// If all type arguments where inferred successfully, index is < 0.
+func (check *Checker) infer(tparams []*TypeName, params *Tuple, args []*operand) (types []Type, index int) {
+       assert(params.Len() == len(args))
+
+       u := newUnifier(check, false)
+       u.x.init(tparams)
+
+       errorf := func(kind string, tpar, targ Type, arg *operand) {
+               // provide a better error message if we can
+               targs, failed := u.x.types()
+               if failed == 0 {
+                       // The first type parameter couldn't be inferred.
+                       // If none of them could be inferred, don't try
+                       // to provide the inferred type in the error msg.
+                       allFailed := true
+                       for _, targ := range targs {
+                               if targ != nil {
+                                       allFailed = false
+                                       break
+                               }
+                       }
+                       if allFailed {
+                               check.errorf(arg, "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeNamesString(tparams))
+                               return
+                       }
+               }
+               smap := makeSubstMap(tparams, targs)
+               inferred := check.subst(arg.Pos(), tpar, smap)
+               if inferred != tpar {
+                       check.errorf(arg, "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar)
+               } else {
+                       check.errorf(arg, "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
+               }
+       }
+
+       // Terminology: generic parameter = function parameter with a type-parameterized type
+
+       // 1st pass: Unify parameter and argument types for generic parameters with typed arguments
+       //           and collect the indices of generic parameters with untyped arguments.
+       var indices []int
+       for i, arg := range args {
+               par := params.At(i)
+               // If we permit bidirectional unification, this conditional code needs to be
+               // executed even if par.typ is not parameterized since the argument may be a
+               // generic function (for which we want to infer // its type arguments).
+               if isParameterized(tparams, par.typ) {
+                       if arg.mode == invalid {
+                               // An error was reported earlier. Ignore this targ
+                               // and continue, we may still be able to infer all
+                               // targs resulting in fewer follon-on errors.
+                               continue
+                       }
+                       if targ := arg.typ; isTyped(targ) {
+                               // If we permit bidirectional unification, and targ is
+                               // a generic function, we need to initialize u.y with
+                               // the respectice type parameters of targ.
+                               if !u.unify(par.typ, targ) {
+                                       errorf("type", par.typ, targ, arg)
+                                       return nil, 0
+                               }
+                       } else {
+                               indices = append(indices, i)
+                       }
+               }
+       }
+
+       // Some generic parameters with untyped arguments may have been given a type
+       // indirectly through another generic parameter with a typed argument; we can
+       // ignore those now. (This only means that we know the types for those generic
+       // parameters; it doesn't mean untyped arguments can be passed safely. We still
+       // need to verify that assignment of those arguments is valid when we check
+       // function parameter passing external to infer.)
+       j := 0
+       for _, i := range indices {
+               par := params.At(i)
+               // Since untyped types are all basic (i.e., non-composite) types, an
+               // untyped argument will never match a composite parameter type; the
+               // only parameter type it can possibly match against is a *TypeParam.
+               // Thus, only keep the indices of generic parameters that are not of
+               // composite types and which don't have a type inferred yet.
+               if tpar, _ := par.typ.(*TypeParam); tpar != nil && u.x.at(tpar.index) == nil {
+                       indices[j] = i
+                       j++
+               }
+       }
+       indices = indices[:j]
+
+       // 2nd pass: Unify parameter and default argument types for remaining generic parameters.
+       for _, i := range indices {
+               par := params.At(i)
+               arg := args[i]
+               targ := Default(arg.typ)
+               // The default type for an untyped nil is untyped nil. We must not
+               // infer an untyped nil type as type parameter type. Ignore untyped
+               // nil by making sure all default argument types are typed.
+               if isTyped(targ) && !u.unify(par.typ, targ) {
+                       errorf("default type", par.typ, targ, arg)
+                       return nil, 0
+               }
+       }
+
+       return u.x.types()
+}
+
+// typeNamesString produces a string containing all the
+// type names in list suitable for human consumption.
+func typeNamesString(list []*TypeName) string {
+       // common cases
+       n := len(list)
+       switch n {
+       case 0:
+               return ""
+       case 1:
+               return list[0].name
+       case 2:
+               return list[0].name + " and " + list[1].name
+       }
+
+       // general case (n > 2)
+       // Would like to use strings.Builder but it's not available in Go 1.4.
+       var b bytes.Buffer
+       for i, tname := range list[:n-1] {
+               if i > 0 {
+                       b.WriteString(", ")
+               }
+               b.WriteString(tname.name)
+       }
+       b.WriteString(", and ")
+       b.WriteString(list[n-1].name)
+       return b.String()
+}
+
+// IsParameterized reports whether typ contains any of the type parameters of tparams.
+func isParameterized(tparams []*TypeName, typ Type) bool {
+       w := tpWalker{
+               seen:    make(map[Type]bool),
+               tparams: tparams,
+       }
+       return w.isParameterized(typ)
+}
+
+type tpWalker struct {
+       seen    map[Type]bool
+       tparams []*TypeName
+}
+
+func (w *tpWalker) isParameterized(typ Type) (res bool) {
+       // detect cycles
+       if x, ok := w.seen[typ]; ok {
+               return x
+       }
+       w.seen[typ] = false
+       defer func() {
+               w.seen[typ] = res
+       }()
+
+       switch t := typ.(type) {
+       case nil, *Basic: // TODO(gri) should nil be handled here?
+               break
+
+       case *Array:
+               return w.isParameterized(t.elem)
+
+       case *Slice:
+               return w.isParameterized(t.elem)
+
+       case *Struct:
+               for _, fld := range t.fields {
+                       if w.isParameterized(fld.typ) {
+                               return true
+                       }
+               }
+
+       case *Pointer:
+               return w.isParameterized(t.base)
+
+       case *Tuple:
+               n := t.Len()
+               for i := 0; i < n; i++ {
+                       if w.isParameterized(t.At(i).typ) {
+                               return true
+                       }
+               }
+
+       case *Sum:
+               return w.isParameterizedList(t.types)
+
+       case *Signature:
+               // t.tparams may not be nil if we are looking at a signature
+               // of a generic function type (or an interface method) that is
+               // part of the type we're testing. We don't care about these type
+               // parameters.
+               // Similarly, the receiver of a method may declare (rather then
+               // use) type parameters, we don't care about those either.
+               // Thus, we only need to look at the input and result parameters.
+               return w.isParameterized(t.params) || w.isParameterized(t.results)
+
+       case *Interface:
+               if t.allMethods != nil {
+                       // interface is complete - quick test
+                       for _, m := range t.allMethods {
+                               if w.isParameterized(m.typ) {
+                                       return true
+                               }
+                       }
+                       return w.isParameterizedList(unpack(t.allTypes))
+               }
+
+               return t.iterate(func(t *Interface) bool {
+                       for _, m := range t.methods {
+                               if w.isParameterized(m.typ) {
+                                       return true
+                               }
+                       }
+                       return w.isParameterizedList(unpack(t.types))
+               }, nil)
+
+       case *Map:
+               return w.isParameterized(t.key) || w.isParameterized(t.elem)
+
+       case *Chan:
+               return w.isParameterized(t.elem)
+
+       case *Named:
+               return w.isParameterizedList(t.targs)
+
+       case *TypeParam:
+               // t must be one of w.tparams
+               return t.index < len(w.tparams) && w.tparams[t.index].typ == t
+
+       case *instance:
+               return w.isParameterizedList(t.targs)
+
+       default:
+               unreachable()
+       }
+
+       return false
+}
+
+func (w *tpWalker) isParameterizedList(list []Type) bool {
+       for _, t := range list {
+               if w.isParameterized(t) {
+                       return true
+               }
+       }
+       return false
+}
+
+// inferB returns the list of actual type arguments inferred from the type parameters'
+// bounds and an initial set of type arguments. If type inference is impossible because
+// unification fails, an error is reported, the resulting types list is nil, and index is 0.
+// Otherwise, types is the list of inferred type arguments, and index is the index of the
+// first type argument in that list that couldn't be inferred (and thus is nil). If all
+// type arguments where inferred successfully, index is < 0. The number of type arguments
+// provided may be less than the number of type parameters, but there must be at least one.
+func (check *Checker) inferB(tparams []*TypeName, targs []Type) (types []Type, index int) {
+       assert(len(tparams) >= len(targs) && len(targs) > 0)
+
+       // Setup bidirectional unification between those structural bounds
+       // and the corresponding type arguments (which may be nil!).
+       u := newUnifier(check, false)
+       u.x.init(tparams)
+       u.y = u.x // type parameters between LHS and RHS of unification are identical
+
+       // Set the type arguments which we know already.
+       for i, targ := range targs {
+               if targ != nil {
+                       u.x.set(i, targ)
+               }
+       }
+
+       // Unify type parameters with their structural constraints, if any.
+       for _, tpar := range tparams {
+               typ := tpar.typ.(*TypeParam)
+               sbound := check.structuralType(typ.bound.Under())
+               if sbound != nil {
+                       //check.dump(">>> unify(%s, %s)", tpar, sbound)
+                       if !u.unify(typ, sbound) {
+                               check.errorf(tpar.pos, "%s does not match %s", tpar, sbound)
+                               return nil, 0
+                       }
+                       //check.dump(">>> => indices = %v, types = %s", u.x.indices, u.types)
+               }
+       }
+
+       // u.x.types() now contains the incoming type arguments plus any additional type
+       // arguments for which there were structural constraints. The newly inferred non-
+       // nil entries may still contain references to other type parameters. For instance,
+       // for [type A interface{}, B interface{type []C}, C interface{type *A}], if A == int
+       // was given, unification produced the type list [int, []C, *A]. We eliminate the
+       // remaining type parameters by substituting the type parameters in this type list
+       // until nothing changes anymore.
+       types, index = u.x.types()
+       if debug {
+               for i, targ := range targs {
+                       assert(targ == nil || types[i] == targ)
+               }
+       }
+
+       // dirty tracks the indices of all types that may still contain type parameters.
+       // We know that nil types entries and entries corresponding to provided (non-nil)
+       // type arguments are clean, so exclude them from the start.
+       var dirty []int
+       for i, typ := range types {
+               if typ != nil && (i >= len(targs) || targs[i] == nil) {
+                       dirty = append(dirty, i)
+               }
+       }
+
+       for len(dirty) > 0 {
+               // TODO(gri) Instead of creating a new smap for each iteration,
+               // provide an update operation for smaps and only change when
+               // needed. Optimization.
+               smap := makeSubstMap(tparams, types)
+               n := 0
+               for _, index := range dirty {
+                       t0 := types[index]
+                       if t1 := check.subst(nopos, t0, smap); t1 != t0 {
+                               types[index] = t1
+                               dirty[n] = index
+                               n++
+                       }
+               }
+               dirty = dirty[:n]
+       }
+       //check.dump(">>> inferred types = %s", types)
+
+       return
+}
+
+// structuralType returns the structural type of a constraint, if any.
+func (check *Checker) structuralType(constraint Type) Type {
+       if iface, _ := constraint.(*Interface); iface != nil {
+               check.completeInterface(nopos, iface)
+               types := unpack(iface.allTypes)
+               if len(types) == 1 {
+                       return types[0]
+               }
+               return nil
+       }
+       return constraint
+}
diff --git a/src/cmd/compile/internal/types2/initorder.go b/src/cmd/compile/internal/types2/initorder.go
new file mode 100644 (file)
index 0000000..a9cabec
--- /dev/null
@@ -0,0 +1,301 @@
+// Copyright 2014 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 (
+       "container/heap"
+       "fmt"
+)
+
+// initOrder computes the Info.InitOrder for package variables.
+func (check *Checker) initOrder() {
+       // An InitOrder may already have been computed if a package is
+       // built from several calls to (*Checker).Files. Clear it.
+       check.Info.InitOrder = check.Info.InitOrder[:0]
+
+       // Compute the object dependency graph and initialize
+       // a priority queue with the list of graph nodes.
+       pq := nodeQueue(dependencyGraph(check.objMap))
+       heap.Init(&pq)
+
+       const debug = false
+       if debug {
+               fmt.Printf("Computing initialization order for %s\n\n", check.pkg)
+               fmt.Println("Object dependency graph:")
+               for obj, d := range check.objMap {
+                       // only print objects that may appear in the dependency graph
+                       if obj, _ := obj.(dependency); obj != nil {
+                               if len(d.deps) > 0 {
+                                       fmt.Printf("\t%s depends on\n", obj.Name())
+                                       for dep := range d.deps {
+                                               fmt.Printf("\t\t%s\n", dep.Name())
+                                       }
+                               } else {
+                                       fmt.Printf("\t%s has no dependencies\n", obj.Name())
+                               }
+                       }
+               }
+               fmt.Println()
+
+               fmt.Println("Transposed object dependency graph (functions eliminated):")
+               for _, n := range pq {
+                       fmt.Printf("\t%s depends on %d nodes\n", n.obj.Name(), n.ndeps)
+                       for p := range n.pred {
+                               fmt.Printf("\t\t%s is dependent\n", p.obj.Name())
+                       }
+               }
+               fmt.Println()
+
+               fmt.Println("Processing nodes:")
+       }
+
+       // Determine initialization order by removing the highest priority node
+       // (the one with the fewest dependencies) and its edges from the graph,
+       // repeatedly, until there are no nodes left.
+       // In a valid Go program, those nodes always have zero dependencies (after
+       // removing all incoming dependencies), otherwise there are initialization
+       // cycles.
+       emitted := make(map[*declInfo]bool)
+       for len(pq) > 0 {
+               // get the next node
+               n := heap.Pop(&pq).(*graphNode)
+
+               if debug {
+                       fmt.Printf("\t%s (src pos %d) depends on %d nodes now\n",
+                               n.obj.Name(), n.obj.order(), n.ndeps)
+               }
+
+               // if n still depends on other nodes, we have a cycle
+               if n.ndeps > 0 {
+                       cycle := findPath(check.objMap, n.obj, n.obj, make(map[Object]bool))
+                       // If n.obj is not part of the cycle (e.g., n.obj->b->c->d->c),
+                       // cycle will be nil. Don't report anything in that case since
+                       // the cycle is reported when the algorithm gets to an object
+                       // in the cycle.
+                       // Furthermore, once an object in the cycle is encountered,
+                       // the cycle will be broken (dependency count will be reduced
+                       // below), and so the remaining nodes in the cycle don't trigger
+                       // another error (unless they are part of multiple cycles).
+                       if cycle != nil {
+                               check.reportCycle(cycle)
+                       }
+                       // Ok to continue, but the variable initialization order
+                       // will be incorrect at this point since it assumes no
+                       // cycle errors.
+               }
+
+               // reduce dependency count of all dependent nodes
+               // and update priority queue
+               for p := range n.pred {
+                       p.ndeps--
+                       heap.Fix(&pq, p.index)
+               }
+
+               // record the init order for variables with initializers only
+               v, _ := n.obj.(*Var)
+               info := check.objMap[v]
+               if v == nil || !info.hasInitializer() {
+                       continue
+               }
+
+               // n:1 variable declarations such as: a, b = f()
+               // introduce a node for each lhs variable (here: a, b);
+               // but they all have the same initializer - emit only
+               // one, for the first variable seen
+               if emitted[info] {
+                       continue // initializer already emitted, if any
+               }
+               emitted[info] = true
+
+               infoLhs := info.lhs // possibly nil (see declInfo.lhs field comment)
+               if infoLhs == nil {
+                       infoLhs = []*Var{v}
+               }
+               init := &Initializer{infoLhs, info.init}
+               check.Info.InitOrder = append(check.Info.InitOrder, init)
+       }
+
+       if debug {
+               fmt.Println()
+               fmt.Println("Initialization order:")
+               for _, init := range check.Info.InitOrder {
+                       fmt.Printf("\t%s\n", init)
+               }
+               fmt.Println()
+       }
+}
+
+// findPath returns the (reversed) list of objects []Object{to, ... from}
+// such that there is a path of object dependencies from 'from' to 'to'.
+// If there is no such path, the result is nil.
+func findPath(objMap map[Object]*declInfo, from, to Object, seen map[Object]bool) []Object {
+       if seen[from] {
+               return nil
+       }
+       seen[from] = true
+
+       for d := range objMap[from].deps {
+               if d == to {
+                       return []Object{d}
+               }
+               if P := findPath(objMap, d, to, seen); P != nil {
+                       return append(P, d)
+               }
+       }
+
+       return nil
+}
+
+// reportCycle reports an error for the given cycle.
+func (check *Checker) reportCycle(cycle []Object) {
+       obj := cycle[0]
+       if check.conf.CompilerErrorMessages {
+               check.errorf(obj, "initialization loop for %s", obj.Name())
+       } else {
+               check.errorf(obj, "initialization cycle for %s", obj.Name())
+       }
+       // subtle loop: print cycle[i] for i = 0, n-1, n-2, ... 1 for len(cycle) = n
+       for i := len(cycle) - 1; i >= 0; i-- {
+               check.errorf(obj, "\t%s refers to", obj.Name()) // secondary error, \t indented
+               obj = cycle[i]
+       }
+       // print cycle[0] again to close the cycle
+       check.errorf(obj, "\t%s", obj.Name())
+}
+
+// ----------------------------------------------------------------------------
+// Object dependency graph
+
+// A dependency is an object that may be a dependency in an initialization
+// expression. Only constants, variables, and functions can be dependencies.
+// Constants are here because constant expression cycles are reported during
+// initialization order computation.
+type dependency interface {
+       Object
+       isDependency()
+}
+
+// A graphNode represents a node in the object dependency graph.
+// Each node p in n.pred represents an edge p->n, and each node
+// s in n.succ represents an edge n->s; with a->b indicating that
+// a depends on b.
+type graphNode struct {
+       obj        dependency // object represented by this node
+       pred, succ nodeSet    // consumers and dependencies of this node (lazily initialized)
+       index      int        // node index in graph slice/priority queue
+       ndeps      int        // number of outstanding dependencies before this object can be initialized
+}
+
+type nodeSet map[*graphNode]bool
+
+func (s *nodeSet) add(p *graphNode) {
+       if *s == nil {
+               *s = make(nodeSet)
+       }
+       (*s)[p] = true
+}
+
+// dependencyGraph computes the object dependency graph from the given objMap,
+// with any function nodes removed. The resulting graph contains only constants
+// and variables.
+func dependencyGraph(objMap map[Object]*declInfo) []*graphNode {
+       // M is the dependency (Object) -> graphNode mapping
+       M := make(map[dependency]*graphNode)
+       for obj := range objMap {
+               // only consider nodes that may be an initialization dependency
+               if obj, _ := obj.(dependency); obj != nil {
+                       M[obj] = &graphNode{obj: obj}
+               }
+       }
+
+       // compute edges for graph M
+       // (We need to include all nodes, even isolated ones, because they still need
+       // to be scheduled for initialization in correct order relative to other nodes.)
+       for obj, n := range M {
+               // for each dependency obj -> d (= deps[i]), create graph edges n->s and s->n
+               for d := range objMap[obj].deps {
+                       // only consider nodes that may be an initialization dependency
+                       if d, _ := d.(dependency); d != nil {
+                               d := M[d]
+                               n.succ.add(d)
+                               d.pred.add(n)
+                       }
+               }
+       }
+
+       // remove function nodes and collect remaining graph nodes in G
+       // (Mutually recursive functions may introduce cycles among themselves
+       // which are permitted. Yet such cycles may incorrectly inflate the dependency
+       // count for variables which in turn may not get scheduled for initialization
+       // in correct order.)
+       var G []*graphNode
+       for obj, n := range M {
+               if _, ok := obj.(*Func); ok {
+                       // connect each predecessor p of n with each successor s
+                       // and drop the function node (don't collect it in G)
+                       for p := range n.pred {
+                               // ignore self-cycles
+                               if p != n {
+                                       // Each successor s of n becomes a successor of p, and
+                                       // each predecessor p of n becomes a predecessor of s.
+                                       for s := range n.succ {
+                                               // ignore self-cycles
+                                               if s != n {
+                                                       p.succ.add(s)
+                                                       s.pred.add(p)
+                                                       delete(s.pred, n) // remove edge to n
+                                               }
+                                       }
+                                       delete(p.succ, n) // remove edge to n
+                               }
+                       }
+               } else {
+                       // collect non-function nodes
+                       G = append(G, n)
+               }
+       }
+
+       // fill in index and ndeps fields
+       for i, n := range G {
+               n.index = i
+               n.ndeps = len(n.succ)
+       }
+
+       return G
+}
+
+// ----------------------------------------------------------------------------
+// Priority queue
+
+// nodeQueue implements the container/heap interface;
+// a nodeQueue may be used as a priority queue.
+type nodeQueue []*graphNode
+
+func (a nodeQueue) Len() int { return len(a) }
+
+func (a nodeQueue) Swap(i, j int) {
+       x, y := a[i], a[j]
+       a[i], a[j] = y, x
+       x.index, y.index = j, i
+}
+
+func (a nodeQueue) Less(i, j int) bool {
+       x, y := a[i], a[j]
+       // nodes are prioritized by number of incoming dependencies (1st key)
+       // and source order (2nd key)
+       return x.ndeps < y.ndeps || x.ndeps == y.ndeps && x.obj.order() < y.obj.order()
+}
+
+func (a *nodeQueue) Push(x interface{}) {
+       panic("unreachable")
+}
+
+func (a *nodeQueue) Pop() interface{} {
+       n := len(*a)
+       x := (*a)[n-1]
+       x.index = -1 // for safety
+       *a = (*a)[:n-1]
+       return x
+}
diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go
new file mode 100644 (file)
index 0000000..f33b7c4
--- /dev/null
@@ -0,0 +1,558 @@
+// UNREVIEWED
+// Copyright 2013 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.
+
+// This file implements tests for various issues.
+
+package types2_test
+
+import (
+       "bytes"
+       "cmd/compile/internal/syntax"
+       "fmt"
+       "internal/testenv"
+       "sort"
+       "strings"
+       "testing"
+
+       . "cmd/compile/internal/types2"
+)
+
+func mustParse(t *testing.T, src string) *syntax.File {
+       f, err := parseSrc("", src)
+       if err != nil {
+               t.Fatal(err)
+       }
+       return f
+}
+func TestIssue5770(t *testing.T) {
+       f := mustParse(t, `package p; type S struct{T}`)
+       var conf Config
+       // conf := Config{Importer: importer.Default()}
+       _, err := conf.Check(f.PkgName.Value, []*syntax.File{f}, nil) // do not crash
+       want := "undeclared name: T"
+       if err == nil || !strings.Contains(err.Error(), want) {
+               t.Errorf("got: %v; want: %s", err, want)
+       }
+}
+
+func TestIssue5849(t *testing.T) {
+       src := `
+package p
+var (
+       s uint
+       _ = uint8(8)
+       _ = uint16(16) << s
+       _ = uint32(32 << s)
+       _ = uint64(64 << s + s)
+       _ = (interface{})("foo")
+       _ = (interface{})(nil)
+)`
+       f := mustParse(t, src)
+
+       var conf Config
+       types := make(map[syntax.Expr]TypeAndValue)
+       _, err := conf.Check(f.PkgName.Value, []*syntax.File{f}, &Info{Types: types})
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       for x, tv := range types {
+               var want Type
+               switch x := x.(type) {
+               case *syntax.BasicLit:
+                       switch x.Value {
+                       case `8`:
+                               want = Typ[Uint8]
+                       case `16`:
+                               want = Typ[Uint16]
+                       case `32`:
+                               want = Typ[Uint32]
+                       case `64`:
+                               want = Typ[Uint] // because of "+ s", s is of type uint
+                       case `"foo"`:
+                               want = Typ[String]
+                       }
+               case *syntax.Name:
+                       if x.Value == "nil" {
+                               want = Typ[UntypedNil]
+                       }
+               }
+               if want != nil && !Identical(tv.Type, want) {
+                       t.Errorf("got %s; want %s", tv.Type, want)
+               }
+       }
+}
+
+func TestIssue6413(t *testing.T) {
+       src := `
+package p
+func f() int {
+       defer f()
+       go f()
+       return 0
+}
+`
+       f := mustParse(t, src)
+
+       var conf Config
+       types := make(map[syntax.Expr]TypeAndValue)
+       _, err := conf.Check(f.PkgName.Value, []*syntax.File{f}, &Info{Types: types})
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       want := Typ[Int]
+       n := 0
+       for x, tv := range types {
+               if _, ok := x.(*syntax.CallExpr); ok {
+                       if tv.Type != want {
+                               t.Errorf("%s: got %s; want %s", x.Pos(), tv.Type, want)
+                       }
+                       n++
+               }
+       }
+
+       if n != 2 {
+               t.Errorf("got %d CallExprs; want 2", n)
+       }
+}
+
+func TestIssue7245(t *testing.T) {
+       src := `
+package p
+func (T) m() (res bool) { return }
+type T struct{} // receiver type after method declaration
+`
+       f := mustParse(t, src)
+
+       var conf Config
+       defs := make(map[*syntax.Name]Object)
+       _, err := conf.Check(f.PkgName.Value, []*syntax.File{f}, &Info{Defs: defs})
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       m := f.DeclList[0].(*syntax.FuncDecl)
+       res1 := defs[m.Name].(*Func).Type().(*Signature).Results().At(0)
+       res2 := defs[m.Type.ResultList[0].Name].(*Var)
+
+       if res1 != res2 {
+               t.Errorf("got %s (%p) != %s (%p)", res1, res2, res1, res2)
+       }
+}
+
+// This tests that uses of existing vars on the LHS of an assignment
+// are Uses, not Defs; and also that the (illegal) use of a non-var on
+// the LHS of an assignment is a Use nonetheless.
+func TestIssue7827(t *testing.T) {
+       const src = `
+package p
+func _() {
+       const w = 1        // defs w
+        x, y := 2, 3       // defs x, y
+        w, x, z := 4, 5, 6 // uses w, x, defs z; error: cannot assign to w
+        _, _, _ = x, y, z  // uses x, y, z
+}
+`
+       f := mustParse(t, src)
+
+       const want = `L3 defs func p._()
+L4 defs const w untyped int
+L5 defs var x int
+L5 defs var y int
+L6 defs var z int
+L6 uses const w untyped int
+L6 uses var x int
+L7 uses var x int
+L7 uses var y int
+L7 uses var z int`
+
+       // don't abort at the first error
+       conf := Config{Error: func(err error) { t.Log(err) }}
+       defs := make(map[*syntax.Name]Object)
+       uses := make(map[*syntax.Name]Object)
+       _, err := conf.Check(f.PkgName.Value, []*syntax.File{f}, &Info{Defs: defs, Uses: uses})
+       if s := fmt.Sprint(err); !strings.HasSuffix(s, "cannot assign to w") {
+               t.Errorf("Check: unexpected error: %s", s)
+       }
+
+       var facts []string
+       for id, obj := range defs {
+               if obj != nil {
+                       fact := fmt.Sprintf("L%d defs %s", id.Pos().Line(), obj)
+                       facts = append(facts, fact)
+               }
+       }
+       for id, obj := range uses {
+               fact := fmt.Sprintf("L%d uses %s", id.Pos().Line(), obj)
+               facts = append(facts, fact)
+       }
+       sort.Strings(facts)
+
+       got := strings.Join(facts, "\n")
+       if got != want {
+               t.Errorf("Unexpected defs/uses\ngot:\n%s\nwant:\n%s", got, want)
+       }
+}
+
+// This tests that the package associated with the types.Object.Pkg method
+// is the type's package independent of the order in which the imports are
+// listed in the sources src1, src2 below.
+// The actual issue is in go/internal/gcimporter which has a corresponding
+// test; we leave this test here to verify correct behavior at the go/types
+// level.
+func TestIssue13898(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       const src0 = `
+package main
+
+import "go/types"
+
+func main() {
+       var info types.Info
+       for _, obj := range info.Uses {
+               _ = obj.Pkg()
+       }
+}
+`
+       // like src0, but also imports go/importer
+       const src1 = `
+package main
+
+import (
+       "go/types"
+       _ "go/importer"
+)
+
+func main() {
+       var info types.Info
+       for _, obj := range info.Uses {
+               _ = obj.Pkg()
+       }
+}
+`
+       // like src1 but with different import order
+       // (used to fail with this issue)
+       const src2 = `
+package main
+
+import (
+       _ "go/importer"
+       "go/types"
+)
+
+func main() {
+       var info types.Info
+       for _, obj := range info.Uses {
+               _ = obj.Pkg()
+       }
+}
+`
+       f := func(test, src string) {
+               f := mustParse(t, src)
+               conf := Config{Importer: defaultImporter()}
+               info := Info{Uses: make(map[*syntax.Name]Object)}
+               _, err := conf.Check("main", []*syntax.File{f}, &info)
+               if err != nil {
+                       t.Fatal(err)
+               }
+
+               var pkg *Package
+               count := 0
+               for id, obj := range info.Uses {
+                       if id.Value == "Pkg" {
+                               pkg = obj.Pkg()
+                               count++
+                       }
+               }
+               if count != 1 {
+                       t.Fatalf("%s: got %d entries named Pkg; want 1", test, count)
+               }
+               if pkg.Name() != "types" {
+                       t.Fatalf("%s: got %v; want package types2", test, pkg)
+               }
+       }
+
+       f("src0", src0)
+       f("src1", src1)
+       f("src2", src2)
+}
+
+func TestIssue22525(t *testing.T) {
+       f := mustParse(t, `package p; func f() { var a, b, c, d, e int }`)
+
+       got := "\n"
+       conf := Config{Error: func(err error) { got += err.Error() + "\n" }}
+       conf.Check(f.PkgName.Value, []*syntax.File{f}, nil) // do not crash
+       want := `
+:1:27: a declared but not used
+:1:30: b declared but not used
+:1:33: c declared but not used
+:1:36: d declared but not used
+:1:39: e declared but not used
+`
+       if got != want {
+               t.Errorf("got: %swant: %s", got, want)
+       }
+}
+
+func TestIssue25627(t *testing.T) {
+       t.Skip("requires syntax tree inspection")
+
+       const prefix = `package p; import "unsafe"; type P *struct{}; type I interface{}; type T `
+       // The src strings (without prefix) are constructed such that the number of semicolons
+       // plus one corresponds to the number of fields expected in the respective struct.
+       for _, src := range []string{
+               `struct { x Missing }`,
+               `struct { Missing }`,
+               `struct { *Missing }`,
+               `struct { unsafe.Pointer }`,
+               `struct { P }`,
+               `struct { *I }`,
+               `struct { a int; b Missing; *Missing }`,
+       } {
+               f := mustParse(t, prefix+src)
+
+               conf := Config{Importer: defaultImporter(), Error: func(err error) {}}
+               info := &Info{Types: make(map[syntax.Expr]TypeAndValue)}
+               _, err := conf.Check(f.PkgName.Value, []*syntax.File{f}, info)
+               if err != nil {
+                       if _, ok := err.(Error); !ok {
+                               t.Fatal(err)
+                       }
+               }
+
+               unimplemented()
+               /*
+                       ast.Inspect(f, func(n syntax.Node) bool {
+                               if spec, _ := n.(*syntax.TypeDecl); spec != nil {
+                                       if tv, ok := info.Types[spec.Type]; ok && spec.Name.Value == "T" {
+                                               want := strings.Count(src, ";") + 1
+                                               if got := tv.Type.(*Struct).NumFields(); got != want {
+                                                       t.Errorf("%s: got %d fields; want %d", src, got, want)
+                                               }
+                                       }
+                               }
+                               return true
+                       })
+               */
+       }
+}
+
+func TestIssue28005(t *testing.T) {
+       // method names must match defining interface name for this test
+       // (see last comment in this function)
+       sources := [...]string{
+               "package p; type A interface{ A() }",
+               "package p; type B interface{ B() }",
+               "package p; type X interface{ A; B }",
+       }
+
+       // compute original file ASTs
+       var orig [len(sources)]*syntax.File
+       for i, src := range sources {
+               orig[i] = mustParse(t, src)
+       }
+
+       // run the test for all order permutations of the incoming files
+       for _, perm := range [][len(sources)]int{
+               {0, 1, 2},
+               {0, 2, 1},
+               {1, 0, 2},
+               {1, 2, 0},
+               {2, 0, 1},
+               {2, 1, 0},
+       } {
+               // create file order permutation
+               files := make([]*syntax.File, len(sources))
+               for i := range perm {
+                       files[i] = orig[perm[i]]
+               }
+
+               // type-check package with given file order permutation
+               var conf Config
+               info := &Info{Defs: make(map[*syntax.Name]Object)}
+               _, err := conf.Check("", files, info)
+               if err != nil {
+                       t.Fatal(err)
+               }
+
+               // look for interface object X
+               var obj Object
+               for name, def := range info.Defs {
+                       if name.Value == "X" {
+                               obj = def
+                               break
+                       }
+               }
+               if obj == nil {
+                       t.Fatal("object X not found")
+               }
+               iface := obj.Type().Interface() // object X must be an interface
+               if iface == nil {
+                       t.Fatalf("%s is not an interface", obj)
+               }
+
+               // Each iface method m is embedded; and m's receiver base type name
+               // must match the method's name per the choice in the source file.
+               for i := 0; i < iface.NumMethods(); i++ {
+                       m := iface.Method(i)
+                       recvName := m.Type().(*Signature).Recv().Type().(*Named).Obj().Name()
+                       if recvName != m.Name() {
+                               t.Errorf("perm %v: got recv %s; want %s", perm, recvName, m.Name())
+                       }
+               }
+       }
+}
+
+func TestIssue28282(t *testing.T) {
+       // create type interface { error }
+       et := Universe.Lookup("error").Type()
+       it := NewInterfaceType(nil, []Type{et})
+       it.Complete()
+       // verify that after completing the interface, the embedded method remains unchanged
+       want := et.Interface().Method(0)
+       got := it.Method(0)
+       if got != want {
+               t.Fatalf("%s.Method(0): got %q (%p); want %q (%p)", it, got, got, want, want)
+       }
+       // verify that lookup finds the same method in both interfaces (redundant check)
+       obj, _, _ := LookupFieldOrMethod(et, false, nil, "Error")
+       if obj != want {
+               t.Fatalf("%s.Lookup: got %q (%p); want %q (%p)", et, obj, obj, want, want)
+       }
+       obj, _, _ = LookupFieldOrMethod(it, false, nil, "Error")
+       if obj != want {
+               t.Fatalf("%s.Lookup: got %q (%p); want %q (%p)", it, obj, obj, want, want)
+       }
+}
+
+func TestIssue29029(t *testing.T) {
+       f1 := mustParse(t, `package p; type A interface { M() }`)
+       f2 := mustParse(t, `package p; var B interface { A }`)
+
+       // printInfo prints the *Func definitions recorded in info, one *Func per line.
+       printInfo := func(info *Info) string {
+               var buf bytes.Buffer
+               for _, obj := range info.Defs {
+                       if fn, ok := obj.(*Func); ok {
+                               fmt.Fprintln(&buf, fn)
+                       }
+               }
+               return buf.String()
+       }
+
+       // The *Func (method) definitions for package p must be the same
+       // independent on whether f1 and f2 are type-checked together, or
+       // incrementally.
+
+       // type-check together
+       var conf Config
+       info := &Info{Defs: make(map[*syntax.Name]Object)}
+       check := NewChecker(&conf, NewPackage("", "p"), info)
+       if err := check.Files([]*syntax.File{f1, f2}); err != nil {
+               t.Fatal(err)
+       }
+       want := printInfo(info)
+
+       // type-check incrementally
+       info = &Info{Defs: make(map[*syntax.Name]Object)}
+       check = NewChecker(&conf, NewPackage("", "p"), info)
+       if err := check.Files([]*syntax.File{f1}); err != nil {
+               t.Fatal(err)
+       }
+       if err := check.Files([]*syntax.File{f2}); err != nil {
+               t.Fatal(err)
+       }
+       got := printInfo(info)
+
+       if got != want {
+               t.Errorf("\ngot : %swant: %s", got, want)
+       }
+}
+
+func TestIssue34151(t *testing.T) {
+       const asrc = `package a; type I interface{ M() }; type T struct { F interface { I } }`
+       const bsrc = `package b; import "a"; type T struct { F interface { a.I } }; var _ = a.T(T{})`
+
+       a, err := pkgFor("a", asrc, nil)
+       if err != nil {
+               t.Fatalf("package %s failed to typecheck: %v", a.Name(), err)
+       }
+
+       bast := mustParse(t, bsrc)
+       conf := Config{Importer: importHelper{a}}
+       b, err := conf.Check(bast.PkgName.Value, []*syntax.File{bast}, nil)
+       if err != nil {
+               t.Errorf("package %s failed to typecheck: %v", b.Name(), err)
+       }
+}
+
+type importHelper struct {
+       pkg *Package
+}
+
+func (h importHelper) Import(path string) (*Package, error) {
+       if path != h.pkg.Path() {
+               return nil, fmt.Errorf("got package path %q; want %q", path, h.pkg.Path())
+       }
+       return h.pkg, nil
+}
+
+// TestIssue34921 verifies that we don't update an imported type's underlying
+// type when resolving an underlying type. Specifically, when determining the
+// underlying type of b.T (which is the underlying type of a.T, which is int)
+// we must not set the underlying type of a.T again since that would lead to
+// a race condition if package b is imported elsewhere, in a package that is
+// concurrently type-checked.
+func TestIssue34921(t *testing.T) {
+       defer func() {
+               if r := recover(); r != nil {
+                       t.Error(r)
+               }
+       }()
+
+       var sources = []string{
+               `package a; type T int`,
+               `package b; import "a"; type T a.T`,
+       }
+
+       var pkg *Package
+       for _, src := range sources {
+               f := mustParse(t, src)
+               conf := Config{Importer: importHelper{pkg}}
+               res, err := conf.Check(f.PkgName.Value, []*syntax.File{f}, nil)
+               if err != nil {
+                       t.Errorf("%q failed to typecheck: %v", src, err)
+               }
+               pkg = res // res is imported by the next package in this test
+       }
+}
+
+func TestIssue43088(t *testing.T) {
+       // type T1 struct {
+       //         x T2
+       // }
+       //
+       // type T2 struct {
+       //         x struct {
+       //                 x T2
+       //         }
+       // }
+       n1 := NewTypeName(syntax.Pos{}, nil, "T1", nil)
+       T1 := NewNamed(n1, nil, nil)
+       n2 := NewTypeName(syntax.Pos{}, nil, "T2", nil)
+       T2 := NewNamed(n2, nil, nil)
+       s1 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "x", T2, false)}, nil)
+       T1.SetUnderlying(s1)
+       s2 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "x", T2, false)}, nil)
+       s3 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "x", s2, false)}, nil)
+       T2.SetUnderlying(s3)
+
+       // These calls must terminate (no endless recursion).
+       Comparable(T1)
+       Comparable(T2)
+}
diff --git a/src/cmd/compile/internal/types2/labels.go b/src/cmd/compile/internal/types2/labels.go
new file mode 100644 (file)
index 0000000..ca5fe6b
--- /dev/null
@@ -0,0 +1,260 @@
+// UNREVIEWED
+// Copyright 2013 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 (
+       "cmd/compile/internal/syntax"
+)
+
+// labels checks correct label use in body.
+func (check *Checker) labels(body *syntax.BlockStmt) {
+       // set of all labels in this body
+       all := NewScope(nil, body.Pos(), endPos(body), "label")
+
+       fwdJumps := check.blockBranches(all, nil, nil, body.List)
+
+       // If there are any forward jumps left, no label was found for
+       // the corresponding goto statements. Either those labels were
+       // never defined, or they are inside blocks and not reachable
+       // for the respective gotos.
+       for _, jmp := range fwdJumps {
+               var msg string
+               name := jmp.Label.Value
+               if alt := all.Lookup(name); alt != nil {
+                       msg = "goto %s jumps into block"
+                       alt.(*Label).used = true // avoid another error
+               } else {
+                       msg = "label %s not declared"
+               }
+               check.errorf(jmp.Label, msg, name)
+       }
+
+       // spec: "It is illegal to define a label that is never used."
+       for _, obj := range all.elems {
+               if lbl := obj.(*Label); !lbl.used {
+                       check.softErrorf(lbl.pos, "label %s declared but not used", lbl.name)
+               }
+       }
+}
+
+// A block tracks label declarations in a block and its enclosing blocks.
+type block struct {
+       parent *block                         // enclosing block
+       lstmt  *syntax.LabeledStmt            // labeled statement to which this block belongs, or nil
+       labels map[string]*syntax.LabeledStmt // allocated lazily
+}
+
+// insert records a new label declaration for the current block.
+// The label must not have been declared before in any block.
+func (b *block) insert(s *syntax.LabeledStmt) {
+       name := s.Label.Value
+       if debug {
+               assert(b.gotoTarget(name) == nil)
+       }
+       labels := b.labels
+       if labels == nil {
+               labels = make(map[string]*syntax.LabeledStmt)
+               b.labels = labels
+       }
+       labels[name] = s
+}
+
+// gotoTarget returns the labeled statement in the current
+// or an enclosing block with the given label name, or nil.
+func (b *block) gotoTarget(name string) *syntax.LabeledStmt {
+       for s := b; s != nil; s = s.parent {
+               if t := s.labels[name]; t != nil {
+                       return t
+               }
+       }
+       return nil
+}
+
+// enclosingTarget returns the innermost enclosing labeled
+// statement with the given label name, or nil.
+func (b *block) enclosingTarget(name string) *syntax.LabeledStmt {
+       for s := b; s != nil; s = s.parent {
+               if t := s.lstmt; t != nil && t.Label.Value == name {
+                       return t
+               }
+       }
+       return nil
+}
+
+// blockBranches processes a block's statement list and returns the set of outgoing forward jumps.
+// all is the scope of all declared labels, parent the set of labels declared in the immediately
+// enclosing block, and lstmt is the labeled statement this block is associated with (or nil).
+func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *syntax.LabeledStmt, list []syntax.Stmt) []*syntax.BranchStmt {
+       b := &block{parent, lstmt, nil}
+
+       var (
+               varDeclPos         syntax.Pos
+               fwdJumps, badJumps []*syntax.BranchStmt
+       )
+
+       // All forward jumps jumping over a variable declaration are possibly
+       // invalid (they may still jump out of the block and be ok).
+       // recordVarDecl records them for the given position.
+       recordVarDecl := func(pos syntax.Pos) {
+               varDeclPos = pos
+               badJumps = append(badJumps[:0], fwdJumps...) // copy fwdJumps to badJumps
+       }
+
+       jumpsOverVarDecl := func(jmp *syntax.BranchStmt) bool {
+               if varDeclPos.IsKnown() {
+                       for _, bad := range badJumps {
+                               if jmp == bad {
+                                       return true
+                               }
+                       }
+               }
+               return false
+       }
+
+       var stmtBranches func(syntax.Stmt)
+       stmtBranches = func(s syntax.Stmt) {
+               switch s := s.(type) {
+               case *syntax.DeclStmt:
+                       for _, d := range s.DeclList {
+                               if d, _ := d.(*syntax.VarDecl); d != nil {
+                                       recordVarDecl(d.Pos())
+                               }
+                       }
+
+               case *syntax.LabeledStmt:
+                       // declare non-blank label
+                       if name := s.Label.Value; name != "_" {
+                               lbl := NewLabel(s.Label.Pos(), check.pkg, name)
+                               if alt := all.Insert(lbl); alt != nil {
+                                       check.softErrorf(lbl.pos, "label %s already declared", name)
+                                       check.reportAltDecl(alt)
+                                       // ok to continue
+                               } else {
+                                       b.insert(s)
+                                       check.recordDef(s.Label, lbl)
+                               }
+                               // resolve matching forward jumps and remove them from fwdJumps
+                               i := 0
+                               for _, jmp := range fwdJumps {
+                                       if jmp.Label.Value == name {
+                                               // match
+                                               lbl.used = true
+                                               check.recordUse(jmp.Label, lbl)
+                                               if jumpsOverVarDecl(jmp) {
+                                                       check.softErrorf(
+                                                               jmp.Label,
+                                                               "goto %s jumps over variable declaration at line %d",
+                                                               name,
+                                                               varDeclPos.Line(),
+                                                       )
+                                                       // ok to continue
+                                               }
+                                       } else {
+                                               // no match - record new forward jump
+                                               fwdJumps[i] = jmp
+                                               i++
+                                       }
+                               }
+                               fwdJumps = fwdJumps[:i]
+                               lstmt = s
+                       }
+                       stmtBranches(s.Stmt)
+
+               case *syntax.BranchStmt:
+                       if s.Label == nil {
+                               return // checked in 1st pass (check.stmt)
+                       }
+
+                       // determine and validate target
+                       name := s.Label.Value
+                       switch s.Tok {
+                       case syntax.Break:
+                               // spec: "If there is a label, it must be that of an enclosing
+                               // "for", "switch", or "select" statement, and that is the one
+                               // whose execution terminates."
+                               valid := false
+                               if t := b.enclosingTarget(name); t != nil {
+                                       switch t.Stmt.(type) {
+                                       case *syntax.SwitchStmt, *syntax.SelectStmt, *syntax.ForStmt:
+                                               valid = true
+                                       }
+                               }
+                               if !valid {
+                                       check.errorf(s.Label, "invalid break label %s", name)
+                                       return
+                               }
+
+                       case syntax.Continue:
+                               // spec: "If there is a label, it must be that of an enclosing
+                               // "for" statement, and that is the one whose execution advances."
+                               valid := false
+                               if t := b.enclosingTarget(name); t != nil {
+                                       switch t.Stmt.(type) {
+                                       case *syntax.ForStmt:
+                                               valid = true
+                                       }
+                               }
+                               if !valid {
+                                       check.errorf(s.Label, "invalid continue label %s", name)
+                                       return
+                               }
+
+                       case syntax.Goto:
+                               if b.gotoTarget(name) == nil {
+                                       // label may be declared later - add branch to forward jumps
+                                       fwdJumps = append(fwdJumps, s)
+                                       return
+                               }
+
+                       default:
+                               check.invalidASTf(s, "branch statement: %s %s", s.Tok, name)
+                               return
+                       }
+
+                       // record label use
+                       obj := all.Lookup(name)
+                       obj.(*Label).used = true
+                       check.recordUse(s.Label, obj)
+
+               case *syntax.AssignStmt:
+                       if s.Op == syntax.Def {
+                               recordVarDecl(s.Pos())
+                       }
+
+               case *syntax.BlockStmt:
+                       // Unresolved forward jumps inside the nested block
+                       // become forward jumps in the current block.
+                       fwdJumps = append(fwdJumps, check.blockBranches(all, b, lstmt, s.List)...)
+
+               case *syntax.IfStmt:
+                       stmtBranches(s.Then)
+                       if s.Else != nil {
+                               stmtBranches(s.Else)
+                       }
+
+               case *syntax.SwitchStmt:
+                       b := &block{b, lstmt, nil}
+                       for _, s := range s.Body {
+                               fwdJumps = append(fwdJumps, check.blockBranches(all, b, nil, s.Body)...)
+                       }
+
+               case *syntax.SelectStmt:
+                       b := &block{b, lstmt, nil}
+                       for _, s := range s.Body {
+                               fwdJumps = append(fwdJumps, check.blockBranches(all, b, nil, s.Body)...)
+                       }
+
+               case *syntax.ForStmt:
+                       stmtBranches(s.Body)
+               }
+       }
+
+       for _, s := range list {
+               stmtBranches(s)
+       }
+
+       return fwdJumps
+}
diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go
new file mode 100644 (file)
index 0000000..e1e7b58
--- /dev/null
@@ -0,0 +1,493 @@
+// UNREVIEWED
+// Copyright 2013 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.
+
+// This file implements various field and method lookup functions.
+
+package types2
+
+// LookupFieldOrMethod looks up a field or method with given package and name
+// in T and returns the corresponding *Var or *Func, an index sequence, and a
+// bool indicating if there were any pointer indirections on the path to the
+// field or method. If addressable is set, T is the type of an addressable
+// variable (only matters for method lookups).
+//
+// The last index entry is the field or method index in the (possibly embedded)
+// type where the entry was found, either:
+//
+//     1) the list of declared methods of a named type; or
+//     2) the list of all methods (method set) of an interface type; or
+//     3) the list of fields of a struct type.
+//
+// The earlier index entries are the indices of the embedded struct fields
+// traversed to get to the found entry, starting at depth 0.
+//
+// If no entry is found, a nil object is returned. In this case, the returned
+// index and indirect values have the following meaning:
+//
+//     - If index != nil, the index sequence points to an ambiguous entry
+//     (the same name appeared more than once at the same embedding level).
+//
+//     - If indirect is set, a method with a pointer receiver type was found
+//      but there was no pointer on the path from the actual receiver type to
+//     the method's formal receiver base type, nor was the receiver addressable.
+//
+func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
+       return (*Checker)(nil).lookupFieldOrMethod(T, addressable, pkg, name)
+}
+
+// Internal use of Checker.lookupFieldOrMethod: If the obj result is a method
+// associated with a concrete (non-interface) type, the method's signature
+// may not be fully set up. Call Checker.objDecl(obj, nil) before accessing
+// the method's type.
+// TODO(gri) Now that we provide the *Checker, we can probably remove this
+// caveat by calling Checker.objDecl from lookupFieldOrMethod. Investigate.
+
+// lookupFieldOrMethod is like the external version but completes interfaces
+// as necessary.
+func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
+       // Methods cannot be associated to a named pointer type
+       // (spec: "The type denoted by T is called the receiver base type;
+       // it must not be a pointer or interface type and it must be declared
+       // in the same package as the method.").
+       // Thus, if we have a named pointer type, proceed with the underlying
+       // pointer type but discard the result if it is a method since we would
+       // not have found it for T (see also issue 8590).
+       if t := T.Named(); t != nil {
+               if p, _ := t.underlying.(*Pointer); p != nil {
+                       obj, index, indirect = check.rawLookupFieldOrMethod(p, false, pkg, name)
+                       if _, ok := obj.(*Func); ok {
+                               return nil, nil, false
+                       }
+                       return
+               }
+       }
+
+       return check.rawLookupFieldOrMethod(T, addressable, pkg, name)
+}
+
+// TODO(gri) The named type consolidation and seen maps below must be
+//           indexed by unique keys for a given type. Verify that named
+//           types always have only one representation (even when imported
+//           indirectly via different packages.)
+
+// rawLookupFieldOrMethod should only be called by lookupFieldOrMethod and missingMethod.
+func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
+       // WARNING: The code in this function is extremely subtle - do not modify casually!
+       //          This function and NewMethodSet should be kept in sync.
+
+       if name == "_" {
+               return // blank fields/methods are never found
+       }
+
+       typ, isPtr := deref(T)
+
+       // *typ where typ is an interface has no methods.
+       // Be cautious: typ may be nil (issue 39634, crash #3).
+       if typ == nil || isPtr && IsInterface(typ) {
+               return
+       }
+
+       // Start with typ as single entry at shallowest depth.
+       current := []embeddedType{{typ, nil, isPtr, false}}
+
+       // Named types that we have seen already, allocated lazily.
+       // Used to avoid endless searches in case of recursive types.
+       // Since only Named types can be used for recursive types, we
+       // only need to track those.
+       // (If we ever allow type aliases to construct recursive types,
+       // we must use type identity rather than pointer equality for
+       // the map key comparison, as we do in consolidateMultiples.)
+       var seen map[*Named]bool
+
+       // search current depth
+       for len(current) > 0 {
+               var next []embeddedType // embedded types found at current depth
+
+               // look for (pkg, name) in all types at current depth
+               var tpar *TypeParam // set if obj receiver is a type parameter
+               for _, e := range current {
+                       typ := e.typ
+
+                       // If we have a named type, we may have associated methods.
+                       // Look for those first.
+                       if named := typ.Named(); named != nil {
+                               if seen[named] {
+                                       // We have seen this type before, at a more shallow depth
+                                       // (note that multiples of this type at the current depth
+                                       // were consolidated before). The type at that depth shadows
+                                       // this same type at the current depth, so we can ignore
+                                       // this one.
+                                       continue
+                               }
+                               if seen == nil {
+                                       seen = make(map[*Named]bool)
+                               }
+                               seen[named] = true
+
+                               // look for a matching attached method
+                               if i, m := lookupMethod(named.methods, pkg, name); m != nil {
+                                       // potential match
+                                       // caution: method may not have a proper signature yet
+                                       index = concat(e.index, i)
+                                       if obj != nil || e.multiples {
+                                               return nil, index, false // collision
+                                       }
+                                       obj = m
+                                       indirect = e.indirect
+                                       continue // we can't have a matching field or interface method
+                               }
+
+                               // continue with underlying type, but only if it's not a type parameter
+                               // TODO(gri) is this what we want to do for type parameters? (spec question)
+                               typ = named.Under()
+                               if typ.TypeParam() != nil {
+                                       continue
+                               }
+                       }
+
+                       tpar = nil
+                       switch t := typ.(type) {
+                       case *Struct:
+                               // look for a matching field and collect embedded types
+                               for i, f := range t.fields {
+                                       if f.sameId(pkg, name) {
+                                               assert(f.typ != nil)
+                                               index = concat(e.index, i)
+                                               if obj != nil || e.multiples {
+                                                       return nil, index, false // collision
+                                               }
+                                               obj = f
+                                               indirect = e.indirect
+                                               continue // we can't have a matching interface method
+                                       }
+                                       // Collect embedded struct fields for searching the next
+                                       // lower depth, but only if we have not seen a match yet
+                                       // (if we have a match it is either the desired field or
+                                       // we have a name collision on the same depth; in either
+                                       // case we don't need to look further).
+                                       // Embedded fields are always of the form T or *T where
+                                       // T is a type name. If e.typ appeared multiple times at
+                                       // this depth, f.typ appears multiple times at the next
+                                       // depth.
+                                       if obj == nil && f.embedded {
+                                               typ, isPtr := deref(f.typ)
+                                               // TODO(gri) optimization: ignore types that can't
+                                               // have fields or methods (only Named, Struct, and
+                                               // Interface types need to be considered).
+                                               next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
+                                       }
+                               }
+
+                       case *Interface:
+                               // look for a matching method
+                               // TODO(gri) t.allMethods is sorted - use binary search
+                               check.completeInterface(nopos, t)
+                               if i, m := lookupMethod(t.allMethods, pkg, name); m != nil {
+                                       assert(m.typ != nil)
+                                       index = concat(e.index, i)
+                                       if obj != nil || e.multiples {
+                                               return nil, index, false // collision
+                                       }
+                                       obj = m
+                                       indirect = e.indirect
+                               }
+
+                       case *TypeParam:
+                               if i, m := lookupMethod(t.Bound().allMethods, pkg, name); m != nil {
+                                       assert(m.typ != nil)
+                                       index = concat(e.index, i)
+                                       if obj != nil || e.multiples {
+                                               return nil, index, false // collision
+                                       }
+                                       tpar = t
+                                       obj = m
+                                       indirect = e.indirect
+                               }
+                               if obj == nil {
+                                       // At this point we're not (yet) looking into methods
+                                       // that any underlyng type of the types in the type list
+                                       // migth have.
+                                       // TODO(gri) Do we want to specify the language that way?
+                               }
+                       }
+               }
+
+               if obj != nil {
+                       // found a potential match
+                       // spec: "A method call x.m() is valid if the method set of (the type of) x
+                       //        contains m and the argument list can be assigned to the parameter
+                       //        list of m. If x is addressable and &x's method set contains m, x.m()
+                       //        is shorthand for (&x).m()".
+                       if f, _ := obj.(*Func); f != nil {
+                               // determine if method has a pointer receiver
+                               hasPtrRecv := tpar == nil && ptrRecv(f)
+                               if hasPtrRecv && !indirect && !addressable {
+                                       return nil, nil, true // pointer/addressable receiver required
+                               }
+                       }
+                       return
+               }
+
+               current = check.consolidateMultiples(next)
+       }
+
+       return nil, nil, false // not found
+}
+
+// embeddedType represents an embedded type
+type embeddedType struct {
+       typ       Type
+       index     []int // embedded field indices, starting with index at depth 0
+       indirect  bool  // if set, there was a pointer indirection on the path to this field
+       multiples bool  // if set, typ appears multiple times at this depth
+}
+
+// consolidateMultiples collects multiple list entries with the same type
+// into a single entry marked as containing multiples. The result is the
+// consolidated list.
+func (check *Checker) consolidateMultiples(list []embeddedType) []embeddedType {
+       if len(list) <= 1 {
+               return list // at most one entry - nothing to do
+       }
+
+       n := 0                     // number of entries w/ unique type
+       prev := make(map[Type]int) // index at which type was previously seen
+       for _, e := range list {
+               if i, found := check.lookupType(prev, e.typ); found {
+                       list[i].multiples = true
+                       // ignore this entry
+               } else {
+                       prev[e.typ] = n
+                       list[n] = e
+                       n++
+               }
+       }
+       return list[:n]
+}
+
+func (check *Checker) lookupType(m map[Type]int, typ Type) (int, bool) {
+       // fast path: maybe the types are equal
+       if i, found := m[typ]; found {
+               return i, true
+       }
+
+       for t, i := range m {
+               if check.identical(t, typ) {
+                       return i, true
+               }
+       }
+
+       return 0, false
+}
+
+// MissingMethod returns (nil, false) if V implements T, otherwise it
+// returns a missing method required by T and whether it is missing or
+// just has the wrong type.
+//
+// For non-interface types V, or if static is set, V implements T if all
+// methods of T are present in V. Otherwise (V is an interface and static
+// is not set), MissingMethod only checks that methods of T which are also
+// present in V have matching types (e.g., for a type assertion x.(T) where
+// x is of interface type V).
+//
+func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
+       m, typ := (*Checker)(nil).missingMethod(V, T, static)
+       return m, typ != nil
+}
+
+// missingMethod is like MissingMethod but accepts a *Checker as
+// receiver and an addressable flag.
+// The receiver may be nil if missingMethod is invoked through
+// an exported API call (such as MissingMethod), i.e., when all
+// methods have been type-checked.
+// If the type has the correctly named method, but with the wrong
+// signature, the existing method is returned as well.
+// To improve error messages, also report the wrong signature
+// when the method exists on *V instead of V.
+func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, wrongType *Func) {
+       check.completeInterface(nopos, T)
+
+       // fast path for common case
+       if T.Empty() {
+               return
+       }
+
+       if ityp := V.Interface(); ityp != nil {
+               check.completeInterface(nopos, ityp)
+               // TODO(gri) allMethods is sorted - can do this more efficiently
+               for _, m := range T.allMethods {
+                       _, f := lookupMethod(ityp.allMethods, m.pkg, m.name)
+
+                       if f == nil {
+                               // if m is the magic method == we're ok (interfaces are comparable)
+                               if m.name == "==" || !static {
+                                       continue
+                               }
+                               return m, f
+                       }
+
+                       // both methods must have the same number of type parameters
+                       ftyp := f.typ.(*Signature)
+                       mtyp := m.typ.(*Signature)
+                       if len(ftyp.tparams) != len(mtyp.tparams) {
+                               return m, f
+                       }
+
+                       // If the methods have type parameters we don't care whether they
+                       // are the same or not, as long as they match up. Use unification
+                       // to see if they can be made to match.
+                       // TODO(gri) is this always correct? what about type bounds?
+                       // (Alternative is to rename/subst type parameters and compare.)
+                       u := newUnifier(check, true)
+                       u.x.init(ftyp.tparams)
+                       if !u.unify(ftyp, mtyp) {
+                               return m, f
+                       }
+               }
+
+               return
+       }
+
+       // A concrete type implements T if it implements all methods of T.
+       Vd, _ := deref(V)
+       Vn := Vd.Named()
+       for _, m := range T.allMethods {
+               // TODO(gri) should this be calling lookupFieldOrMethod instead (and why not)?
+               obj, _, _ := check.rawLookupFieldOrMethod(V, false, m.pkg, m.name)
+
+               // Check if *V implements this method of T.
+               if obj == nil {
+                       ptr := NewPointer(V)
+                       obj, _, _ = check.rawLookupFieldOrMethod(ptr, false, m.pkg, m.name)
+                       if obj != nil {
+                               return m, obj.(*Func)
+                       }
+               }
+
+               // we must have a method (not a field of matching function type)
+               f, _ := obj.(*Func)
+               if f == nil {
+                       // if m is the magic method == and V is comparable, we're ok
+                       if m.name == "==" && Comparable(V) {
+                               continue
+                       }
+                       return m, nil
+               }
+
+               // methods may not have a fully set up signature yet
+               if check != nil {
+                       check.objDecl(f, nil)
+               }
+
+               // both methods must have the same number of type parameters
+               ftyp := f.typ.(*Signature)
+               mtyp := m.typ.(*Signature)
+               if len(ftyp.tparams) != len(mtyp.tparams) {
+                       return m, f
+               }
+
+               // If V is a (instantiated) generic type, its methods are still
+               // parameterized using the original (declaration) receiver type
+               // parameters (subst simply copies the existing method list, it
+               // does not instantiate the methods).
+               // 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 && len(Vn.tparams) > 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) != len(Vn.targs) {
+                               return
+                       }
+                       ftyp = check.subst(nopos, ftyp, makeSubstMap(ftyp.rparams, Vn.targs)).(*Signature)
+               }
+
+               // If the methods have type parameters we don't care whether they
+               // are the same or not, as long as they match up. Use unification
+               // to see if they can be made to match.
+               // TODO(gri) is this always correct? what about type bounds?
+               // (Alternative is to rename/subst type parameters and compare.)
+               u := newUnifier(check, true)
+               u.x.init(ftyp.tparams)
+               if !u.unify(ftyp, mtyp) {
+                       return m, f
+               }
+       }
+
+       return
+}
+
+// assertableTo reports whether a value of type V can be asserted to have type T.
+// It returns (nil, false) as affirmative answer. Otherwise it returns a missing
+// method required by V and whether it is missing or just has the wrong type.
+// The receiver may be nil if assertableTo is invoked through an exported API call
+// (such as AssertableTo), i.e., when all methods have been type-checked.
+// If strict (or the global constant forceStrict) is set, assertions that
+// are known to fail are not permitted.
+func (check *Checker) assertableTo(V *Interface, T Type, strict bool) (method, wrongType *Func) {
+       // no static check is required if T is an interface
+       // spec: "If T is an interface type, x.(T) asserts that the
+       //        dynamic type of x implements the interface T."
+       if T.Interface() != nil && !(strict || forceStrict) {
+               return
+       }
+       return check.missingMethod(T, V, false)
+}
+
+// deref dereferences typ if it is a *Pointer and returns its base and true.
+// Otherwise it returns (typ, false).
+func deref(typ Type) (Type, bool) {
+       if p, _ := typ.(*Pointer); p != nil {
+               return p.base, true
+       }
+       return typ, false
+}
+
+// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a
+// (named or unnamed) struct and returns its base. Otherwise it returns typ.
+func derefStructPtr(typ Type) Type {
+       if p := typ.Pointer(); p != nil {
+               if p.base.Struct() != nil {
+                       return p.base
+               }
+       }
+       return typ
+}
+
+// concat returns the result of concatenating list and i.
+// The result does not share its underlying array with list.
+func concat(list []int, i int) []int {
+       var t []int
+       t = append(t, list...)
+       return append(t, i)
+}
+
+// fieldIndex returns the index for the field with matching package and name, or a value < 0.
+func fieldIndex(fields []*Var, pkg *Package, name string) int {
+       if name != "_" {
+               for i, f := range fields {
+                       if f.sameId(pkg, name) {
+                               return i
+                       }
+               }
+       }
+       return -1
+}
+
+// lookupMethod returns the index of and method with matching package and name, or (-1, nil).
+func lookupMethod(methods []*Func, pkg *Package, name string) (int, *Func) {
+       if name != "_" {
+               for i, m := range methods {
+                       if m.sameId(pkg, name) {
+                               return i, m
+                       }
+               }
+       }
+       return -1, nil
+}
diff --git a/src/cmd/compile/internal/types2/methodset.go b/src/cmd/compile/internal/types2/methodset.go
new file mode 100644 (file)
index 0000000..eb8f122
--- /dev/null
@@ -0,0 +1,262 @@
+// UNREVIEWED
+// Copyright 2013 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.
+
+// This file implements method sets.
+
+package types2
+
+import (
+       "bytes"
+       "fmt"
+       "sort"
+)
+
+// A MethodSet is an ordered set of concrete or abstract (interface) methods;
+// a method is a MethodVal selection, and they are ordered by ascending m.Obj().Id().
+// The zero value for a MethodSet is a ready-to-use empty method set.
+type MethodSet struct {
+       list []*Selection
+}
+
+func (s *MethodSet) String() string {
+       if s.Len() == 0 {
+               return "MethodSet {}"
+       }
+
+       // Would like to use strings.Builder but it's not available in Go 1.4.
+       var buf bytes.Buffer
+       fmt.Fprintln(&buf, "MethodSet {")
+       for _, f := range s.list {
+               fmt.Fprintf(&buf, "\t%s\n", f)
+       }
+       fmt.Fprintln(&buf, "}")
+       return buf.String()
+}
+
+// Len returns the number of methods in s.
+func (s *MethodSet) Len() int { return len(s.list) }
+
+// At returns the i'th method in s for 0 <= i < s.Len().
+func (s *MethodSet) At(i int) *Selection { return s.list[i] }
+
+// Lookup returns the method with matching package and name, or nil if not found.
+func (s *MethodSet) Lookup(pkg *Package, name string) *Selection {
+       if s.Len() == 0 {
+               return nil
+       }
+
+       key := Id(pkg, name)
+       i := sort.Search(len(s.list), func(i int) bool {
+               m := s.list[i]
+               return m.obj.Id() >= key
+       })
+       if i < len(s.list) {
+               m := s.list[i]
+               if m.obj.Id() == key {
+                       return m
+               }
+       }
+       return nil
+}
+
+// Shared empty method set.
+var emptyMethodSet MethodSet
+
+// Note: NewMethodSet is intended for external use only as it
+//       requires interfaces to be complete. If may be used
+//       internally if LookupFieldOrMethod completed the same
+//       interfaces beforehand.
+
+// NewMethodSet returns the method set for the given type T.
+// It always returns a non-nil method set, even if it is empty.
+func NewMethodSet(T Type) *MethodSet {
+       // WARNING: The code in this function is extremely subtle - do not modify casually!
+       //          This function and lookupFieldOrMethod should be kept in sync.
+
+       // method set up to the current depth, allocated lazily
+       var base methodSet
+
+       typ, isPtr := deref(T)
+
+       // *typ where typ is an interface has no methods.
+       if isPtr && IsInterface(typ) {
+               return &emptyMethodSet
+       }
+
+       // Start with typ as single entry at shallowest depth.
+       current := []embeddedType{{typ, nil, isPtr, false}}
+
+       // Named types that we have seen already, allocated lazily.
+       // Used to avoid endless searches in case of recursive types.
+       // Since only Named types can be used for recursive types, we
+       // only need to track those.
+       // (If we ever allow type aliases to construct recursive types,
+       // we must use type identity rather than pointer equality for
+       // the map key comparison, as we do in consolidateMultiples.)
+       var seen map[*Named]bool
+
+       // collect methods at current depth
+       for len(current) > 0 {
+               var next []embeddedType // embedded types found at current depth
+
+               // field and method sets at current depth, indexed by names (Id's), and allocated lazily
+               var fset map[string]bool // we only care about the field names
+               var mset methodSet
+
+               for _, e := range current {
+                       typ := e.typ
+
+                       // If we have a named type, we may have associated methods.
+                       // Look for those first.
+                       if named := typ.Named(); named != nil {
+                               if seen[named] {
+                                       // We have seen this type before, at a more shallow depth
+                                       // (note that multiples of this type at the current depth
+                                       // were consolidated before). The type at that depth shadows
+                                       // this same type at the current depth, so we can ignore
+                                       // this one.
+                                       continue
+                               }
+                               if seen == nil {
+                                       seen = make(map[*Named]bool)
+                               }
+                               seen[named] = true
+
+                               mset = mset.add(named.methods, e.index, e.indirect, e.multiples)
+
+                               // continue with underlying type
+                               typ = named.underlying
+                       }
+
+                       switch t := typ.(type) {
+                       case *Struct:
+                               for i, f := range t.fields {
+                                       if fset == nil {
+                                               fset = make(map[string]bool)
+                                       }
+                                       fset[f.Id()] = true
+
+                                       // Embedded fields are always of the form T or *T where
+                                       // T is a type name. If typ appeared multiple times at
+                                       // this depth, f.Type appears multiple times at the next
+                                       // depth.
+                                       if f.embedded {
+                                               typ, isPtr := deref(f.typ)
+                                               // TODO(gri) optimization: ignore types that can't
+                                               // have fields or methods (only Named, Struct, and
+                                               // Interface types need to be considered).
+                                               next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
+                                       }
+                               }
+
+                       case *Interface:
+                               mset = mset.add(t.allMethods, e.index, true, e.multiples)
+                       }
+               }
+
+               // Add methods and collisions at this depth to base if no entries with matching
+               // names exist already.
+               for k, m := range mset {
+                       if _, found := base[k]; !found {
+                               // Fields collide with methods of the same name at this depth.
+                               if fset[k] {
+                                       m = nil // collision
+                               }
+                               if base == nil {
+                                       base = make(methodSet)
+                               }
+                               base[k] = m
+                       }
+               }
+
+               // Add all (remaining) fields at this depth as collisions (since they will
+               // hide any method further down) if no entries with matching names exist already.
+               for k := range fset {
+                       if _, found := base[k]; !found {
+                               if base == nil {
+                                       base = make(methodSet)
+                               }
+                               base[k] = nil // collision
+                       }
+               }
+
+               // It's ok to call consolidateMultiples with a nil *Checker because
+               // MethodSets are not used internally (outside debug mode). When used
+               // externally, interfaces are expected to be completed and then we do
+               // not need a *Checker to complete them when (indirectly) calling
+               // Checker.identical via consolidateMultiples.
+               current = (*Checker)(nil).consolidateMultiples(next)
+       }
+
+       if len(base) == 0 {
+               return &emptyMethodSet
+       }
+
+       // collect methods
+       var list []*Selection
+       for _, m := range base {
+               if m != nil {
+                       m.recv = T
+                       list = append(list, m)
+               }
+       }
+       // sort by unique name
+       sort.Slice(list, func(i, j int) bool {
+               return list[i].obj.Id() < list[j].obj.Id()
+       })
+       return &MethodSet{list}
+}
+
+// A methodSet is a set of methods and name collisions.
+// A collision indicates that multiple methods with the
+// same unique id, or a field with that id appeared.
+type methodSet map[string]*Selection // a nil entry indicates a name collision
+
+// Add adds all functions in list to the method set s.
+// If multiples is set, every function in list appears multiple times
+// and is treated as a collision.
+func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool) methodSet {
+       if len(list) == 0 {
+               return s
+       }
+       if s == nil {
+               s = make(methodSet)
+       }
+       for i, f := range list {
+               key := f.Id()
+               // if f is not in the set, add it
+               if !multiples {
+                       // TODO(gri) A found method may not be added because it's not in the method set
+                       // (!indirect && ptrRecv(f)). A 2nd method on the same level may be in the method
+                       // set and may not collide with the first one, thus leading to a false positive.
+                       // Is that possible? Investigate.
+                       if _, found := s[key]; !found && (indirect || !ptrRecv(f)) {
+                               s[key] = &Selection{MethodVal, nil, f, concat(index, i), indirect}
+                               continue
+                       }
+               }
+               s[key] = nil // collision
+       }
+       return s
+}
+
+// ptrRecv reports whether the receiver is of the form *T.
+func ptrRecv(f *Func) bool {
+       // If a method's receiver type is set, use that as the source of truth for the receiver.
+       // Caution: Checker.funcDecl (decl.go) marks a function by setting its type to an empty
+       // signature. We may reach here before the signature is fully set up: we must explicitly
+       // check if the receiver is set (we cannot just look for non-nil f.typ).
+       if sig, _ := f.typ.(*Signature); sig != nil && sig.recv != nil {
+               _, isPtr := deref(sig.recv.typ)
+               return isPtr
+       }
+
+       // If a method's type is not set it may be a method/function that is:
+       // 1) client-supplied (via NewFunc with no signature), or
+       // 2) internally created but not yet type-checked.
+       // For case 1) we can't do anything; the client must know what they are doing.
+       // For case 2) we can use the information gathered by the resolver.
+       return f.hasPtrRecv
+}
diff --git a/src/cmd/compile/internal/types2/object.go b/src/cmd/compile/internal/types2/object.go
new file mode 100644 (file)
index 0000000..42fae76
--- /dev/null
@@ -0,0 +1,498 @@
+// UNREVIEWED
+// Copyright 2013 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"
+       "cmd/compile/internal/syntax"
+       "fmt"
+       "go/constant"
+       "unicode"
+       "unicode/utf8"
+)
+
+// An Object describes a named language entity such as a package,
+// constant, type, variable, function (incl. methods), or label.
+// All objects implement the Object interface.
+//
+type Object interface {
+       Parent() *Scope  // scope in which this object is declared; nil for methods and struct fields
+       Pos() syntax.Pos // position of object identifier in declaration
+       Pkg() *Package   // package to which this object belongs; nil for labels and objects in the Universe scope
+       Name() string    // package local object name
+       Type() Type      // object type
+       Exported() bool  // reports whether the name starts with a capital letter
+       Id() string      // object name if exported, qualified name if not exported (see func Id)
+
+       // String returns a human-readable string of the object.
+       String() string
+
+       // order reflects a package-level object's source order: if object
+       // a is before object b in the source, then a.order() < b.order().
+       // order returns a value > 0 for package-level objects; it returns
+       // 0 for all other objects (including objects in file scopes).
+       order() uint32
+
+       // color returns the object's color.
+       color() color
+
+       // setType sets the type of the object.
+       setType(Type)
+
+       // setOrder sets the order number of the object. It must be > 0.
+       setOrder(uint32)
+
+       // setColor sets the object's color. It must not be white.
+       setColor(color color)
+
+       // setParent sets the parent scope of the object.
+       setParent(*Scope)
+
+       // sameId reports whether obj.Id() and Id(pkg, name) are the same.
+       sameId(pkg *Package, name string) bool
+
+       // scopePos returns the start position of the scope of this Object
+       scopePos() syntax.Pos
+
+       // setScopePos sets the start position of the scope for this Object.
+       setScopePos(pos syntax.Pos)
+}
+
+func isExported(name string) bool {
+       ch, _ := utf8.DecodeRuneInString(name)
+       return unicode.IsUpper(ch)
+}
+
+// Id returns name if it is exported, otherwise it
+// returns the name qualified with the package path.
+func Id(pkg *Package, name string) string {
+       if isExported(name) {
+               return name
+       }
+       // unexported names need the package path for differentiation
+       // (if there's no package, make sure we don't start with '.'
+       // as that may change the order of methods between a setup
+       // inside a package and outside a package - which breaks some
+       // tests)
+       path := "_"
+       // pkg is nil for objects in Universe scope and possibly types
+       // introduced via Eval (see also comment in object.sameId)
+       if pkg != nil && pkg.path != "" {
+               path = pkg.path
+       }
+       return path + "." + name
+}
+
+// An object implements the common parts of an Object.
+type object struct {
+       parent    *Scope
+       pos       syntax.Pos
+       pkg       *Package
+       name      string
+       typ       Type
+       order_    uint32
+       color_    color
+       scopePos_ syntax.Pos
+}
+
+// color encodes the color of an object (see Checker.objDecl for details).
+type color uint32
+
+// An object may be painted in one of three colors.
+// Color values other than white or black are considered grey.
+const (
+       white color = iota
+       black
+       grey // must be > white and black
+)
+
+func (c color) String() string {
+       switch c {
+       case white:
+               return "white"
+       case black:
+               return "black"
+       default:
+               return "grey"
+       }
+}
+
+// colorFor returns the (initial) color for an object depending on
+// whether its type t is known or not.
+func colorFor(t Type) color {
+       if t != nil {
+               return black
+       }
+       return white
+}
+
+// Parent returns the scope in which the object is declared.
+// The result is nil for methods and struct fields.
+func (obj *object) Parent() *Scope { return obj.parent }
+
+// Pos returns the declaration position of the object's identifier.
+func (obj *object) Pos() syntax.Pos { return obj.pos }
+
+// Pkg returns the package to which the object belongs.
+// The result is nil for labels and objects in the Universe scope.
+func (obj *object) Pkg() *Package { return obj.pkg }
+
+// Name returns the object's (package-local, unqualified) name.
+func (obj *object) Name() string { return obj.name }
+
+// Type returns the object's type.
+func (obj *object) Type() Type { return obj.typ }
+
+// Exported reports whether the object is exported (starts with a capital letter).
+// It doesn't take into account whether the object is in a local (function) scope
+// or not.
+func (obj *object) Exported() bool { return isExported(obj.name) }
+
+// Id is a wrapper for Id(obj.Pkg(), obj.Name()).
+func (obj *object) Id() string { return Id(obj.pkg, obj.name) }
+
+func (obj *object) String() string       { panic("abstract") }
+func (obj *object) order() uint32        { return obj.order_ }
+func (obj *object) color() color         { return obj.color_ }
+func (obj *object) scopePos() syntax.Pos { return obj.scopePos_ }
+
+func (obj *object) setParent(parent *Scope)    { obj.parent = parent }
+func (obj *object) setType(typ Type)           { obj.typ = typ }
+func (obj *object) setOrder(order uint32)      { assert(order > 0); obj.order_ = order }
+func (obj *object) setColor(color color)       { assert(color != white); obj.color_ = color }
+func (obj *object) setScopePos(pos syntax.Pos) { obj.scopePos_ = pos }
+
+func (obj *object) sameId(pkg *Package, name string) bool {
+       // spec:
+       // "Two identifiers are different if they are spelled differently,
+       // or if they appear in different packages and are not exported.
+       // Otherwise, they are the same."
+       if name != obj.name {
+               return false
+       }
+       // obj.Name == name
+       if obj.Exported() {
+               return true
+       }
+       // not exported, so packages must be the same (pkg == nil for
+       // fields in Universe scope; this can only happen for types
+       // introduced via Eval)
+       if pkg == nil || obj.pkg == nil {
+               return pkg == obj.pkg
+       }
+       // pkg != nil && obj.pkg != nil
+       return pkg.path == obj.pkg.path
+}
+
+// A PkgName represents an imported Go package.
+// PkgNames don't have a type.
+type PkgName struct {
+       object
+       imported *Package
+       used     bool // set if the package was used
+}
+
+// NewPkgName returns a new PkgName object representing an imported package.
+// The remaining arguments set the attributes found with all Objects.
+func NewPkgName(pos syntax.Pos, pkg *Package, name string, imported *Package) *PkgName {
+       return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, black, nopos}, imported, false}
+}
+
+// Imported returns the package that was imported.
+// It is distinct from Pkg(), which is the package containing the import statement.
+func (obj *PkgName) Imported() *Package { return obj.imported }
+
+// A Const represents a declared constant.
+type Const struct {
+       object
+       val constant.Value
+}
+
+// NewConst returns a new constant with value val.
+// The remaining arguments set the attributes found with all Objects.
+func NewConst(pos syntax.Pos, pkg *Package, name string, typ Type, val constant.Value) *Const {
+       return &Const{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, val}
+}
+
+// Val returns the constant's value.
+func (obj *Const) Val() constant.Value { return obj.val }
+
+func (*Const) isDependency() {} // a constant may be a dependency of an initialization expression
+
+// A TypeName represents a name for a (defined or alias) type.
+type TypeName struct {
+       object
+}
+
+// NewTypeName returns a new type name denoting the given typ.
+// The remaining arguments set the attributes found with all Objects.
+//
+// The typ argument may be a defined (Named) type or an alias type.
+// It may also be nil such that the returned TypeName can be used as
+// argument for NewNamed, which will set the TypeName's type as a side-
+// effect.
+func NewTypeName(pos syntax.Pos, pkg *Package, name string, typ Type) *TypeName {
+       return &TypeName{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}}
+}
+
+// IsAlias reports whether obj is an alias name for a type.
+func (obj *TypeName) IsAlias() bool {
+       switch t := obj.typ.(type) {
+       case nil:
+               return false
+       case *Basic:
+               // unsafe.Pointer is not an alias.
+               if obj.pkg == Unsafe {
+                       return false
+               }
+               // Any user-defined type name for a basic type is an alias for a
+               // basic type (because basic types are pre-declared in the Universe
+               // scope, outside any package scope), and so is any type name with
+               // a different name than the name of the basic type it refers to.
+               // Additionally, we need to look for "byte" and "rune" because they
+               // are aliases but have the same names (for better error messages).
+               return obj.pkg != nil || t.name != obj.name || t == universeByte || t == universeRune
+       case *Named:
+               return obj != t.obj
+       default:
+               return true
+       }
+}
+
+// A Variable represents a declared variable (including function parameters and results, and struct fields).
+type Var struct {
+       object
+       embedded bool // if set, the variable is an embedded struct field, and name is the type name
+       isField  bool // var is struct field
+       used     bool // set if the variable was used
+}
+
+// NewVar returns a new variable.
+// The arguments set the attributes found with all Objects.
+func NewVar(pos syntax.Pos, pkg *Package, name string, typ Type) *Var {
+       return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}}
+}
+
+// NewParam returns a new variable representing a function parameter.
+func NewParam(pos syntax.Pos, pkg *Package, name string, typ Type) *Var {
+       return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, used: true} // parameters are always 'used'
+}
+
+// NewField returns a new variable representing a struct field.
+// For embedded fields, the name is the unqualified type name
+/// under which the field is accessible.
+func NewField(pos syntax.Pos, pkg *Package, name string, typ Type, embedded bool) *Var {
+       return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, embedded: embedded, isField: true}
+}
+
+// Anonymous reports whether the variable is an embedded field.
+// Same as Embedded; only present for backward-compatibility.
+func (obj *Var) Anonymous() bool { return obj.embedded }
+
+// Embedded reports whether the variable is an embedded field.
+func (obj *Var) Embedded() bool { return obj.embedded }
+
+// IsField reports whether the variable is a struct field.
+func (obj *Var) IsField() bool { return obj.isField }
+
+func (*Var) isDependency() {} // a variable may be a dependency of an initialization expression
+
+// A Func represents a declared function, concrete method, or abstract
+// (interface) method. Its Type() is always a *Signature.
+// An abstract method may belong to many interfaces due to embedding.
+type Func struct {
+       object
+       hasPtrRecv bool // only valid for methods that don't have a type yet
+}
+
+// NewFunc returns a new function with the given signature, representing
+// the function's type.
+func NewFunc(pos syntax.Pos, pkg *Package, name string, sig *Signature) *Func {
+       // don't store a (typed) nil signature
+       var typ Type
+       if sig != nil {
+               typ = sig
+       }
+       return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, false}
+}
+
+// FullName returns the package- or receiver-type-qualified name of
+// function or method obj.
+func (obj *Func) FullName() string {
+       var buf bytes.Buffer
+       writeFuncName(&buf, obj, nil)
+       return buf.String()
+}
+
+// Scope returns the scope of the function's body block.
+func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
+
+func (*Func) isDependency() {} // a function may be a dependency of an initialization expression
+
+// A Label represents a declared label.
+// Labels don't have a type.
+type Label struct {
+       object
+       used bool // set if the label was used
+}
+
+// NewLabel returns a new label.
+func NewLabel(pos syntax.Pos, pkg *Package, name string) *Label {
+       return &Label{object{pos: pos, pkg: pkg, name: name, typ: Typ[Invalid], color_: black}, false}
+}
+
+// A Builtin represents a built-in function.
+// Builtins don't have a valid type.
+type Builtin struct {
+       object
+       id builtinId
+}
+
+func newBuiltin(id builtinId) *Builtin {
+       return &Builtin{object{name: predeclaredFuncs[id].name, typ: Typ[Invalid], color_: black}, id}
+}
+
+// Nil represents the predeclared value nil.
+type Nil struct {
+       object
+}
+
+func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
+       var tname *TypeName
+       typ := obj.Type()
+
+       switch obj := obj.(type) {
+       case *PkgName:
+               fmt.Fprintf(buf, "package %s", obj.Name())
+               if path := obj.imported.path; path != "" && path != obj.name {
+                       fmt.Fprintf(buf, " (%q)", path)
+               }
+               return
+
+       case *Const:
+               buf.WriteString("const")
+
+       case *TypeName:
+               tname = obj
+               buf.WriteString("type")
+
+       case *Var:
+               if obj.isField {
+                       buf.WriteString("field")
+               } else {
+                       buf.WriteString("var")
+               }
+
+       case *Func:
+               buf.WriteString("func ")
+               writeFuncName(buf, obj, qf)
+               if typ != nil {
+                       WriteSignature(buf, typ.(*Signature), qf)
+               }
+               return
+
+       case *Label:
+               buf.WriteString("label")
+               typ = nil
+
+       case *Builtin:
+               buf.WriteString("builtin")
+               typ = nil
+
+       case *Nil:
+               buf.WriteString("nil")
+               return
+
+       default:
+               panic(fmt.Sprintf("writeObject(%T)", obj))
+       }
+
+       buf.WriteByte(' ')
+
+       // For package-level objects, qualify the name.
+       if obj.Pkg() != nil && obj.Pkg().scope.Lookup(obj.Name()) == obj {
+               writePackage(buf, obj.Pkg(), qf)
+       }
+       buf.WriteString(obj.Name())
+
+       if typ == nil {
+               return
+       }
+
+       if tname != nil {
+               // We have a type object: Don't print anything more for
+               // basic types since there's no more information (names
+               // are the same; see also comment in TypeName.IsAlias).
+               if _, ok := typ.(*Basic); ok {
+                       return
+               }
+               if tname.IsAlias() {
+                       buf.WriteString(" =")
+               } else {
+                       typ = typ.Under()
+               }
+       }
+
+       buf.WriteByte(' ')
+       WriteType(buf, typ, qf)
+}
+
+func writePackage(buf *bytes.Buffer, pkg *Package, qf Qualifier) {
+       if pkg == nil {
+               return
+       }
+       var s string
+       if qf != nil {
+               s = qf(pkg)
+       } else {
+               s = pkg.Path()
+       }
+       if s != "" {
+               buf.WriteString(s)
+               buf.WriteByte('.')
+       }
+}
+
+// ObjectString returns the string form of obj.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func ObjectString(obj Object, qf Qualifier) string {
+       var buf bytes.Buffer
+       writeObject(&buf, obj, qf)
+       return buf.String()
+}
+
+func (obj *PkgName) String() string  { return ObjectString(obj, nil) }
+func (obj *Const) String() string    { return ObjectString(obj, nil) }
+func (obj *TypeName) String() string { return ObjectString(obj, nil) }
+func (obj *Var) String() string      { return ObjectString(obj, nil) }
+func (obj *Func) String() string     { return ObjectString(obj, nil) }
+func (obj *Label) String() string    { return ObjectString(obj, nil) }
+func (obj *Builtin) String() string  { return ObjectString(obj, nil) }
+func (obj *Nil) String() string      { return ObjectString(obj, nil) }
+
+func writeFuncName(buf *bytes.Buffer, f *Func, qf Qualifier) {
+       if f.typ != nil {
+               sig := f.typ.(*Signature)
+               if recv := sig.Recv(); recv != nil {
+                       buf.WriteByte('(')
+                       if _, ok := recv.Type().(*Interface); ok {
+                               // gcimporter creates abstract methods of
+                               // named interfaces using the interface type
+                               // (not the named type) as the receiver.
+                               // Don't print it in full.
+                               buf.WriteString("interface")
+                       } else {
+                               WriteType(buf, recv.Type(), qf)
+                       }
+                       buf.WriteByte(')')
+                       buf.WriteByte('.')
+               } else if f.pkg != nil {
+                       writePackage(buf, f.pkg, qf)
+               }
+       }
+       buf.WriteString(f.name)
+}
diff --git a/src/cmd/compile/internal/types2/object_test.go b/src/cmd/compile/internal/types2/object_test.go
new file mode 100644 (file)
index 0000000..8f11c87
--- /dev/null
@@ -0,0 +1,89 @@
+// UNREVIEWED
+// Copyright 2016 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 (
+       "cmd/compile/internal/syntax"
+       "strings"
+       "testing"
+)
+
+func parseSrc(path, src string) (*syntax.File, error) {
+       return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), nil, nil, 0)
+}
+
+func TestIsAlias(t *testing.T) {
+       check := func(obj *TypeName, want bool) {
+               if got := obj.IsAlias(); got != want {
+                       t.Errorf("%v: got IsAlias = %v; want %v", obj, got, want)
+               }
+       }
+
+       // predeclared types
+       check(Unsafe.Scope().Lookup("Pointer").(*TypeName), false)
+       for _, name := range Universe.Names() {
+               if obj, _ := Universe.Lookup(name).(*TypeName); obj != nil {
+                       check(obj, name == "byte" || name == "rune")
+               }
+       }
+
+       // various other types
+       pkg := NewPackage("p", "p")
+       t1 := NewTypeName(nopos, pkg, "t1", nil)
+       n1 := NewNamed(t1, new(Struct), nil)
+       for _, test := range []struct {
+               name  *TypeName
+               alias bool
+       }{
+               {NewTypeName(nopos, nil, "t0", nil), false}, // no type yet
+               {NewTypeName(nopos, pkg, "t0", nil), false}, // no type yet
+               {t1, false}, // type name refers to named type and vice versa
+               {NewTypeName(nopos, nil, "t2", &emptyInterface), true}, // type name refers to unnamed type
+               {NewTypeName(nopos, pkg, "t3", n1), true},              // type name refers to named type with different type name
+               {NewTypeName(nopos, nil, "t4", Typ[Int32]), true},      // type name refers to basic type with different name
+               {NewTypeName(nopos, nil, "int32", Typ[Int32]), false},  // type name refers to basic type with same name
+               {NewTypeName(nopos, pkg, "int32", Typ[Int32]), true},   // type name is declared in user-defined package (outside Universe)
+               {NewTypeName(nopos, nil, "rune", Typ[Rune]), true},     // type name refers to basic type rune which is an alias already
+       } {
+               check(test.name, test.alias)
+       }
+}
+
+// TestEmbeddedMethod checks that an embedded method is represented by
+// the same Func Object as the original method. See also issue #34421.
+func TestEmbeddedMethod(t *testing.T) {
+       const src = `package p; type I interface { error }`
+
+       // type-check src
+       f, err := parseSrc("", src)
+       if err != nil {
+               t.Fatalf("parse failed: %s", err)
+       }
+       var conf Config
+       pkg, err := conf.Check(f.PkgName.Value, []*syntax.File{f}, nil)
+       if err != nil {
+               t.Fatalf("typecheck failed: %s", err)
+       }
+
+       // get original error.Error method
+       eface := Universe.Lookup("error")
+       orig, _, _ := LookupFieldOrMethod(eface.Type(), false, nil, "Error")
+       if orig == nil {
+               t.Fatalf("original error.Error not found")
+       }
+
+       // get embedded error.Error method
+       iface := pkg.Scope().Lookup("I")
+       embed, _, _ := LookupFieldOrMethod(iface.Type(), false, nil, "Error")
+       if embed == nil {
+               t.Fatalf("embedded error.Error not found")
+       }
+
+       // original and embedded Error object should be identical
+       if orig != embed {
+               t.Fatalf("%s (%p) != %s (%p)", orig, orig, embed, embed)
+       }
+}
diff --git a/src/cmd/compile/internal/types2/objset.go b/src/cmd/compile/internal/types2/objset.go
new file mode 100644 (file)
index 0000000..88ff0af
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2013 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.
+
+// This file implements objsets.
+//
+// An objset is similar to a Scope but objset elements
+// are identified by their unique id, instead of their
+// object name.
+
+package types2
+
+// An objset is a set of objects identified by their unique id.
+// The zero value for objset is a ready-to-use empty objset.
+type objset map[string]Object // initialized lazily
+
+// insert attempts to insert an object obj into objset s.
+// If s already contains an alternative object alt with
+// the same name, insert leaves s unchanged and returns alt.
+// Otherwise it inserts obj and returns nil.
+func (s *objset) insert(obj Object) Object {
+       id := obj.Id()
+       if alt := (*s)[id]; alt != nil {
+               return alt
+       }
+       if *s == nil {
+               *s = make(map[string]Object)
+       }
+       (*s)[id] = obj
+       return nil
+}
diff --git a/src/cmd/compile/internal/types2/operand.go b/src/cmd/compile/internal/types2/operand.go
new file mode 100644 (file)
index 0000000..0a19760
--- /dev/null
@@ -0,0 +1,321 @@
+// UNREVIEWED
+// Copyright 2012 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.
+
+// This file defines operands and associated operations.
+
+package types2
+
+import (
+       "bytes"
+       "cmd/compile/internal/syntax"
+       "fmt"
+       "go/constant"
+       "go/token"
+)
+
+// An operandMode specifies the (addressing) mode of an operand.
+type operandMode byte
+
+const (
+       invalid   operandMode = iota // operand is invalid
+       novalue                      // operand represents no value (result of a function call w/o result)
+       builtin                      // operand is a built-in function
+       typexpr                      // operand is a type
+       constant_                    // operand is a constant; the operand's typ is a Basic type
+       variable                     // operand is an addressable variable
+       mapindex                     // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)
+       value                        // operand is a computed value
+       commaok                      // like value, but operand may be used in a comma,ok expression
+       commaerr                     // like commaok, but second value is error, not boolean
+       cgofunc                      // operand is a cgo function
+)
+
+var operandModeString = [...]string{
+       invalid:   "invalid operand",
+       novalue:   "no value",
+       builtin:   "built-in",
+       typexpr:   "type",
+       constant_: "constant",
+       variable:  "variable",
+       mapindex:  "map index expression",
+       value:     "value",
+       commaok:   "comma, ok expression",
+       commaerr:  "comma, error expression",
+       cgofunc:   "cgo function",
+}
+
+// An operand represents an intermediate value during type checking.
+// Operands have an (addressing) mode, the expression evaluating to
+// the operand, the operand's type, a value for constants, and an id
+// for built-in functions.
+// The zero value of operand is a ready to use invalid operand.
+//
+type operand struct {
+       mode operandMode
+       expr syntax.Expr
+       typ  Type
+       val  constant.Value
+       id   builtinId
+}
+
+// Pos returns the position of the expression corresponding to x.
+// If x is invalid the position is nopos.
+//
+func (x *operand) Pos() syntax.Pos {
+       // x.expr may not be set if x is invalid
+       if x.expr == nil {
+               return nopos
+       }
+       return x.expr.Pos()
+}
+
+// Operand string formats
+// (not all "untyped" cases can appear due to the type system,
+// but they fall out naturally here)
+//
+// mode       format
+//
+// invalid    <expr> (               <mode>                    )
+// novalue    <expr> (               <mode>                    )
+// builtin    <expr> (               <mode>                    )
+// typexpr    <expr> (               <mode>                    )
+//
+// constant   <expr> (<untyped kind> <mode>                    )
+// constant   <expr> (               <mode>       of type <typ>)
+// constant   <expr> (<untyped kind> <mode> <val>              )
+// constant   <expr> (               <mode> <val> of type <typ>)
+//
+// variable   <expr> (<untyped kind> <mode>                    )
+// variable   <expr> (               <mode>       of type <typ>)
+//
+// mapindex   <expr> (<untyped kind> <mode>                    )
+// mapindex   <expr> (               <mode>       of type <typ>)
+//
+// value      <expr> (<untyped kind> <mode>                    )
+// value      <expr> (               <mode>       of type <typ>)
+//
+// commaok    <expr> (<untyped kind> <mode>                    )
+// commaok    <expr> (               <mode>       of type <typ>)
+//
+// commaerr   <expr> (<untyped kind> <mode>                    )
+// commaerr   <expr> (               <mode>       of type <typ>)
+//
+// cgofunc    <expr> (<untyped kind> <mode>                    )
+// cgofunc    <expr> (               <mode>       of type <typ>)
+//
+func operandString(x *operand, qf Qualifier) string {
+       var buf bytes.Buffer
+
+       var expr string
+       if x.expr != nil {
+               expr = ExprString(x.expr)
+       } else {
+               switch x.mode {
+               case builtin:
+                       expr = predeclaredFuncs[x.id].name
+               case typexpr:
+                       expr = TypeString(x.typ, qf)
+               case constant_:
+                       expr = x.val.String()
+               }
+       }
+
+       // <expr> (
+       if expr != "" {
+               buf.WriteString(expr)
+               buf.WriteString(" (")
+       }
+
+       // <untyped kind>
+       hasType := false
+       switch x.mode {
+       case invalid, novalue, builtin, typexpr:
+               // no type
+       default:
+               // should have a type, but be cautious (don't crash during printing)
+               if x.typ != nil {
+                       if isUntyped(x.typ) {
+                               buf.WriteString(x.typ.(*Basic).name)
+                               buf.WriteByte(' ')
+                               break
+                       }
+                       hasType = true
+               }
+       }
+
+       // <mode>
+       buf.WriteString(operandModeString[x.mode])
+
+       // <val>
+       if x.mode == constant_ {
+               if s := x.val.String(); s != expr {
+                       buf.WriteByte(' ')
+                       buf.WriteString(s)
+               }
+       }
+
+       // <typ>
+       if hasType {
+               if x.typ != Typ[Invalid] {
+                       var intro string
+                       switch {
+                       case isGeneric(x.typ):
+                               intro = " of generic type "
+                       case x.typ.TypeParam() != nil:
+                               intro = " of type parameter type "
+                       default:
+                               intro = " of type "
+                       }
+                       buf.WriteString(intro)
+                       WriteType(&buf, x.typ, qf)
+               } else {
+                       buf.WriteString(" with invalid type")
+               }
+       }
+
+       // )
+       if expr != "" {
+               buf.WriteByte(')')
+       }
+
+       return buf.String()
+}
+
+func (x *operand) String() string {
+       return operandString(x, nil)
+}
+
+// setConst sets x to the untyped constant for literal lit.
+func (x *operand) setConst(k syntax.LitKind, lit string) {
+       var tok token.Token
+       var kind BasicKind
+       switch k {
+       case syntax.IntLit:
+               tok = token.INT
+               kind = UntypedInt
+       case syntax.FloatLit:
+               tok = token.FLOAT
+               kind = UntypedFloat
+       case syntax.ImagLit:
+               tok = token.IMAG
+               kind = UntypedComplex
+       case syntax.RuneLit:
+               tok = token.CHAR
+               kind = UntypedRune
+       case syntax.StringLit:
+               tok = token.STRING
+               kind = UntypedString
+       default:
+               unreachable()
+       }
+
+       val := constant.MakeFromLiteral(lit, tok, 0)
+       if val.Kind() == constant.Unknown {
+               x.mode = invalid
+               x.typ = Typ[Invalid]
+               return
+       }
+       x.mode = constant_
+       x.typ = Typ[kind]
+       x.val = val
+}
+
+// isNil reports whether x is the nil value.
+func (x *operand) isNil() bool {
+       return x.mode == value && x.typ == Typ[UntypedNil]
+}
+
+// TODO(gri) The functions operand.assignableTo, checker.convertUntyped,
+//           checker.representable, and checker.assignment are
+//           overlapping in functionality. Need to simplify and clean up.
+
+// assignableTo reports whether x is assignable to a variable of type T.
+// If the result is false and a non-nil reason is provided, it may be set
+// to a more detailed explanation of the failure (result != "").
+// The check parameter may be nil if assignableTo is invoked through
+// an exported API call, i.e., when all methods have been type-checked.
+func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool {
+       if x.mode == invalid || T == Typ[Invalid] {
+               return true // avoid spurious errors
+       }
+
+       V := x.typ
+
+       // x's type is identical to T
+       if check.identical(V, T) {
+               return true
+       }
+
+       Vu := optype(V.Under())
+       Tu := optype(T.Under())
+
+       // x is an untyped value representable by a value of type T
+       // TODO(gri) This is borrowing from checker.convertUntyped and
+       //           checker.representable. Need to clean up.
+       if isUntyped(Vu) {
+               switch t := Tu.(type) {
+               case *Basic:
+                       if x.isNil() && t.kind == UnsafePointer {
+                               return true
+                       }
+                       if x.mode == constant_ {
+                               return representableConst(x.val, check, t, nil)
+                       }
+                       // The result of a comparison is an untyped boolean,
+                       // but may not be a constant.
+                       if Vb, _ := Vu.(*Basic); Vb != nil {
+                               return Vb.kind == UntypedBool && isBoolean(Tu)
+                       }
+               case *Sum:
+                       return t.is(func(t Type) bool {
+                               // TODO(gri) this could probably be more efficient
+                               return x.assignableTo(check, t, reason)
+                       })
+               case *Interface:
+                       check.completeInterface(nopos, t)
+                       return x.isNil() || t.Empty()
+               case *Pointer, *Signature, *Slice, *Map, *Chan:
+                       return x.isNil()
+               }
+       }
+       // Vu is typed
+
+       // x's type V and T have identical underlying types
+       // and at least one of V or T is not a named type
+       if check.identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
+               return true
+       }
+
+       // T is an interface type and x implements T
+       if Ti, ok := Tu.(*Interface); ok {
+               if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ {
+                       if reason != nil {
+                               if wrongType != nil {
+                                       if check.identical(m.typ, wrongType.typ) {
+                                               *reason = fmt.Sprintf("missing method %s (%s has pointer receiver)", m.name, m.name)
+                                       } else {
+                                               *reason = fmt.Sprintf("wrong type for method %s (have %s, want %s)", m.Name(), wrongType.typ, m.typ)
+                                       }
+
+                               } else {
+                                       *reason = "missing method " + m.Name()
+                               }
+                       }
+                       return false
+               }
+               return true
+       }
+
+       // x is a bidirectional channel value, T is a channel
+       // type, x's type V and T have identical element types,
+       // and at least one of V or T is not a named type
+       if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
+               if Tc, ok := Tu.(*Chan); ok && check.identical(Vc.elem, Tc.elem) {
+                       return !isNamed(V) || !isNamed(T)
+               }
+       }
+
+       return false
+}
diff --git a/src/cmd/compile/internal/types2/package.go b/src/cmd/compile/internal/types2/package.go
new file mode 100644 (file)
index 0000000..31b1e71
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2013 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 (
+       "fmt"
+)
+
+// A Package describes a Go package.
+type Package struct {
+       path     string
+       name     string
+       scope    *Scope
+       complete bool
+       imports  []*Package
+       fake     bool // scope lookup errors are silently dropped if package is fake (internal use only)
+       cgo      bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
+}
+
+// NewPackage returns a new Package for the given package path and name.
+// The package is not complete and contains no explicit imports.
+func NewPackage(path, name string) *Package {
+       scope := NewScope(Universe, nopos, nopos, fmt.Sprintf("package %q", path))
+       return &Package{path: path, name: name, scope: scope}
+}
+
+// Path returns the package path.
+func (pkg *Package) Path() string { return pkg.path }
+
+// Name returns the package name.
+func (pkg *Package) Name() string { return pkg.name }
+
+// SetName sets the package name.
+func (pkg *Package) SetName(name string) { pkg.name = name }
+
+// Scope returns the (complete or incomplete) package scope
+// holding the objects declared at package level (TypeNames,
+// Consts, Vars, and Funcs).
+func (pkg *Package) Scope() *Scope { return pkg.scope }
+
+// A package is complete if its scope contains (at least) all
+// exported objects; otherwise it is incomplete.
+func (pkg *Package) Complete() bool { return pkg.complete }
+
+// MarkComplete marks a package as complete.
+func (pkg *Package) MarkComplete() { pkg.complete = true }
+
+// Imports returns the list of packages directly imported by
+// pkg; the list is in source order.
+//
+// If pkg was loaded from export data, Imports includes packages that
+// provide package-level objects referenced by pkg. This may be more or
+// less than the set of packages directly imported by pkg's source code.
+func (pkg *Package) Imports() []*Package { return pkg.imports }
+
+// SetImports sets the list of explicitly imported packages to list.
+// It is the caller's responsibility to make sure list elements are unique.
+func (pkg *Package) SetImports(list []*Package) { pkg.imports = list }
+
+func (pkg *Package) String() string {
+       return fmt.Sprintf("package %s (%q)", pkg.name, pkg.path)
+}
diff --git a/src/cmd/compile/internal/types2/pos.go b/src/cmd/compile/internal/types2/pos.go
new file mode 100644 (file)
index 0000000..4dd839b
--- /dev/null
@@ -0,0 +1,364 @@
+// UNREVIEWED
+// Copyright 2012 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.
+
+// This file implements helper functions for scope position computations.
+
+package types2
+
+import "cmd/compile/internal/syntax"
+
+// startPos returns the start position of n.
+func startPos(n syntax.Node) syntax.Pos {
+       // Cases for nodes which don't need a correction are commented out.
+       for m := n; ; {
+               switch n := m.(type) {
+               case nil:
+                       panic("internal error: nil")
+
+               // packages
+               case *syntax.File:
+                       // file block starts at the beginning of the file
+                       return syntax.MakePos(n.Pos().Base(), 1, 1)
+
+               // declarations
+               // case *syntax.ImportDecl:
+               // case *syntax.ConstDecl:
+               // case *syntax.TypeDecl:
+               // case *syntax.VarDecl:
+               // case *syntax.FuncDecl:
+
+               // expressions
+               // case *syntax.BadExpr:
+               // case *syntax.Name:
+               // case *syntax.BasicLit:
+               case *syntax.CompositeLit:
+                       if n.Type != nil {
+                               m = n.Type
+                               continue
+                       }
+                       return n.Pos()
+               // case *syntax.KeyValueExpr:
+               // case *syntax.FuncLit:
+               // case *syntax.ParenExpr:
+               case *syntax.SelectorExpr:
+                       m = n.X
+               case *syntax.IndexExpr:
+                       m = n.X
+               // case *syntax.SliceExpr:
+               case *syntax.AssertExpr:
+                       m = n.X
+               case *syntax.TypeSwitchGuard:
+                       if n.Lhs != nil {
+                               m = n.Lhs
+                               continue
+                       }
+                       m = n.X
+               case *syntax.Operation:
+                       if n.Y != nil {
+                               m = n.X
+                               continue
+                       }
+                       return n.Pos()
+               case *syntax.CallExpr:
+                       m = n.Fun
+               case *syntax.ListExpr:
+                       if len(n.ElemList) > 0 {
+                               m = n.ElemList[0]
+                               continue
+                       }
+                       return n.Pos()
+               // types
+               // case *syntax.ArrayType:
+               // case *syntax.SliceType:
+               // case *syntax.DotsType:
+               // case *syntax.StructType:
+               // case *syntax.Field:
+               // case *syntax.InterfaceType:
+               // case *syntax.FuncType:
+               // case *syntax.MapType:
+               // case *syntax.ChanType:
+
+               // statements
+               // case *syntax.EmptyStmt:
+               // case *syntax.LabeledStmt:
+               // case *syntax.BlockStmt:
+               // case *syntax.ExprStmt:
+               case *syntax.SendStmt:
+                       m = n.Chan
+               // case *syntax.DeclStmt:
+               case *syntax.AssignStmt:
+                       m = n.Lhs
+               // case *syntax.BranchStmt:
+               // case *syntax.CallStmt:
+               // case *syntax.ReturnStmt:
+               // case *syntax.IfStmt:
+               // case *syntax.ForStmt:
+               // case *syntax.SwitchStmt:
+               // case *syntax.SelectStmt:
+
+               // helper nodes
+               case *syntax.RangeClause:
+                       if n.Lhs != nil {
+                               m = n.Lhs
+                               continue
+                       }
+                       m = n.X
+               // case *syntax.CaseClause:
+               // case *syntax.CommClause:
+
+               default:
+                       return n.Pos()
+               }
+       }
+}
+
+// endPos returns the approximate end position of n in the source.
+// For some nodes (*syntax.Name, *syntax.BasicLit) it returns
+// the position immediately following the node; for others
+// (*syntax.BlockStmt, *syntax.SwitchStmt, etc.) it returns
+// the position of the closing '}'; and for some (*syntax.ParenExpr)
+// the returned position is the end position of the last enclosed
+// expression.
+// Thus, endPos should not be used for exact demarcation of the
+// end of a node in the source; it is mostly useful to determine
+// scope ranges where there is some leeway.
+func endPos(n syntax.Node) syntax.Pos {
+       for m := n; ; {
+               switch n := m.(type) {
+               case nil:
+                       panic("internal error: nil")
+
+               // packages
+               case *syntax.File:
+                       return n.EOF
+
+               // declarations
+               case *syntax.ImportDecl:
+                       m = n.Path
+               case *syntax.ConstDecl:
+                       if n.Values != nil {
+                               m = n.Values
+                               continue
+                       }
+                       if n.Type != nil {
+                               m = n.Type
+                               continue
+                       }
+                       if l := len(n.NameList); l > 0 {
+                               m = n.NameList[l-1]
+                               continue
+                       }
+                       return n.Pos()
+               case *syntax.TypeDecl:
+                       m = n.Type
+               case *syntax.VarDecl:
+                       if n.Values != nil {
+                               m = n.Values
+                               continue
+                       }
+                       if n.Type != nil {
+                               m = n.Type
+                               continue
+                       }
+                       if l := len(n.NameList); l > 0 {
+                               m = n.NameList[l-1]
+                               continue
+                       }
+                       return n.Pos()
+               case *syntax.FuncDecl:
+                       if n.Body != nil {
+                               m = n.Body
+                               continue
+                       }
+                       m = n.Type
+
+               // expressions
+               case *syntax.BadExpr:
+                       return n.Pos()
+               case *syntax.Name:
+                       p := n.Pos()
+                       return syntax.MakePos(p.Base(), p.Line(), p.Col()+uint(len(n.Value)))
+               case *syntax.BasicLit:
+                       p := n.Pos()
+                       return syntax.MakePos(p.Base(), p.Line(), p.Col()+uint(len(n.Value)))
+               case *syntax.CompositeLit:
+                       return n.Rbrace
+               case *syntax.KeyValueExpr:
+                       m = n.Value
+               case *syntax.FuncLit:
+                       m = n.Body
+               case *syntax.ParenExpr:
+                       m = n.X
+               case *syntax.SelectorExpr:
+                       m = n.Sel
+               case *syntax.IndexExpr:
+                       m = n.Index
+               case *syntax.SliceExpr:
+                       for i := len(n.Index) - 1; i >= 0; i-- {
+                               if x := n.Index[i]; x != nil {
+                                       m = x
+                                       continue
+                               }
+                       }
+                       m = n.X
+               case *syntax.AssertExpr:
+                       m = n.Type
+               case *syntax.TypeSwitchGuard:
+                       m = n.X
+               case *syntax.Operation:
+                       if n.Y != nil {
+                               m = n.Y
+                               continue
+                       }
+                       m = n.X
+               case *syntax.CallExpr:
+                       if l := lastExpr(n.ArgList); l != nil {
+                               m = l
+                               continue
+                       }
+                       m = n.Fun
+               case *syntax.ListExpr:
+                       if l := lastExpr(n.ElemList); l != nil {
+                               m = l
+                               continue
+                       }
+                       return n.Pos()
+
+               // types
+               case *syntax.ArrayType:
+                       m = n.Elem
+               case *syntax.SliceType:
+                       m = n.Elem
+               case *syntax.DotsType:
+                       m = n.Elem
+               case *syntax.StructType:
+                       if l := lastField(n.FieldList); l != nil {
+                               m = l
+                               continue
+                       }
+                       return n.Pos()
+                       // TODO(gri) need to take TagList into account
+               case *syntax.Field:
+                       if n.Type != nil {
+                               m = n.Type
+                               continue
+                       }
+                       m = n.Name
+               case *syntax.InterfaceType:
+                       if l := lastField(n.MethodList); l != nil {
+                               m = l
+                               continue
+                       }
+                       return n.Pos()
+               case *syntax.FuncType:
+                       if l := lastField(n.ResultList); l != nil {
+                               m = l
+                               continue
+                       }
+                       if l := lastField(n.ParamList); l != nil {
+                               m = l
+                               continue
+                       }
+                       return n.Pos()
+               case *syntax.MapType:
+                       m = n.Value
+               case *syntax.ChanType:
+                       m = n.Elem
+
+               // statements
+               case *syntax.EmptyStmt:
+                       return n.Pos()
+               case *syntax.LabeledStmt:
+                       m = n.Stmt
+               case *syntax.BlockStmt:
+                       return n.Rbrace
+               case *syntax.ExprStmt:
+                       m = n.X
+               case *syntax.SendStmt:
+                       m = n.Value
+               case *syntax.DeclStmt:
+                       if l := lastDecl(n.DeclList); l != nil {
+                               m = l
+                               continue
+                       }
+                       return n.Pos()
+               case *syntax.AssignStmt:
+                       m = n.Rhs
+               case *syntax.BranchStmt:
+                       if n.Label != nil {
+                               m = n.Label
+                               continue
+                       }
+                       return n.Pos()
+               case *syntax.CallStmt:
+                       m = n.Call
+               case *syntax.ReturnStmt:
+                       if n.Results != nil {
+                               m = n.Results
+                               continue
+                       }
+                       return n.Pos()
+               case *syntax.IfStmt:
+                       if n.Else != nil {
+                               m = n.Else
+                               continue
+                       }
+                       m = n.Then
+               case *syntax.ForStmt:
+                       m = n.Body
+               case *syntax.SwitchStmt:
+                       return n.Rbrace
+               case *syntax.SelectStmt:
+                       return n.Rbrace
+
+               // helper nodes
+               case *syntax.RangeClause:
+                       m = n.X
+               case *syntax.CaseClause:
+                       if l := lastStmt(n.Body); l != nil {
+                               m = l
+                               continue
+                       }
+                       return n.Colon
+               case *syntax.CommClause:
+                       if l := lastStmt(n.Body); l != nil {
+                               m = l
+                               continue
+                       }
+                       return n.Colon
+
+               default:
+                       return n.Pos()
+               }
+       }
+}
+
+func lastDecl(list []syntax.Decl) syntax.Decl {
+       if l := len(list); l > 0 {
+               return list[l-1]
+       }
+       return nil
+}
+
+func lastExpr(list []syntax.Expr) syntax.Expr {
+       if l := len(list); l > 0 {
+               return list[l-1]
+       }
+       return nil
+}
+
+func lastStmt(list []syntax.Stmt) syntax.Stmt {
+       if l := len(list); l > 0 {
+               return list[l-1]
+       }
+       return nil
+}
+
+func lastField(list []*syntax.Field) *syntax.Field {
+       if l := len(list); l > 0 {
+               return list[l-1]
+       }
+       return nil
+}
diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go
new file mode 100644 (file)
index 0000000..b910d8d
--- /dev/null
@@ -0,0 +1,428 @@
+// Copyright 2012 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.
+
+// This file implements commonly used type predicates.
+
+package types2
+
+import (
+       "sort"
+)
+
+// isNamed reports whether typ has a name.
+// isNamed may be called with types that are not fully set up.
+func isNamed(typ Type) bool {
+       switch typ.(type) {
+       case *Basic, *Named, *TypeParam, *instance:
+               return true
+       }
+       return false
+}
+
+// isGeneric reports whether a type is a generic, uninstantiated type (generic
+// signatures are not included).
+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.tparams != nil && named.targs == nil
+}
+
+func is(typ Type, what BasicInfo) bool {
+       switch t := optype(typ.Under()).(type) {
+       case *Basic:
+               return t.info&what != 0
+       case *Sum:
+               return t.is(func(typ Type) bool { return is(typ, what) })
+       }
+       return false
+}
+
+func isBoolean(typ Type) bool  { return is(typ, IsBoolean) }
+func isInteger(typ Type) bool  { return is(typ, IsInteger) }
+func isUnsigned(typ Type) bool { return is(typ, IsUnsigned) }
+func isFloat(typ Type) bool    { return is(typ, IsFloat) }
+func isComplex(typ Type) bool  { return is(typ, IsComplex) }
+func isNumeric(typ Type) bool  { return is(typ, IsNumeric) }
+func isString(typ Type) bool   { return is(typ, IsString) }
+
+// Note that if typ is a type parameter, isInteger(typ) || isFloat(typ) does not
+// produce the expected result because a type list that contains both an integer
+// and a floating-point type is neither (all) integers, nor (all) floats.
+// Use isIntegerOrFloat instead.
+func isIntegerOrFloat(typ Type) bool { return is(typ, IsInteger|IsFloat) }
+
+// isNumericOrString is the equivalent of isIntegerOrFloat for isNumeric(typ) || isString(typ).
+func isNumericOrString(typ Type) bool { return is(typ, IsNumeric|IsString) }
+
+// isTyped reports whether typ is typed; i.e., not an untyped
+// constant or boolean. isTyped may be called with types that
+// are not fully set up.
+func isTyped(typ Type) bool {
+       // isTyped is called with types that are not fully
+       // set up. Must not call Basic()!
+       // A *Named or *instance type is always typed, so
+       // we only need to check if we have a true *Basic
+       // type.
+       t, _ := typ.(*Basic)
+       return t == nil || t.info&IsUntyped == 0
+}
+
+// isUntyped(typ) is the same as !isTyped(typ).
+func isUntyped(typ Type) bool {
+       return !isTyped(typ)
+}
+
+func isOrdered(typ Type) bool { return is(typ, IsOrdered) }
+
+func isConstType(typ Type) bool {
+       t := typ.Basic()
+       return t != nil && t.info&IsConstType != 0
+}
+
+// IsInterface reports whether typ is an interface type.
+func IsInterface(typ Type) bool {
+       return typ.Interface() != nil
+}
+
+// Comparable reports whether values of type T are comparable.
+func Comparable(T Type) bool {
+       return comparable(T, nil)
+}
+
+func comparable(T Type, seen map[Type]bool) bool {
+       if seen[T] {
+               return true
+       }
+       if seen == nil {
+               seen = make(map[Type]bool)
+       }
+       seen[T] = true
+
+       // If T is a type parameter not constrained by any type
+       // list (i.e., it's underlying type is the top type),
+       // T is comparable if it has the == method. Otherwise,
+       // the underlying type "wins". For instance
+       //
+       //     interface{ comparable; type []byte }
+       //
+       // is not comparable because []byte is not comparable.
+       if t := T.TypeParam(); t != nil && optype(t) == theTop {
+               return t.Bound().IsComparable()
+       }
+
+       switch t := optype(T.Under()).(type) {
+       case *Basic:
+               // assume invalid types to be comparable
+               // to avoid follow-up errors
+               return t.kind != UntypedNil
+       case *Pointer, *Interface, *Chan:
+               return true
+       case *Struct:
+               for _, f := range t.fields {
+                       if !comparable(f.typ, seen) {
+                               return false
+                       }
+               }
+               return true
+       case *Array:
+               return comparable(t.elem, seen)
+       case *Sum:
+               pred := func(t Type) bool {
+                       return comparable(t, seen)
+               }
+               return t.is(pred)
+       case *TypeParam:
+               return t.Bound().IsComparable()
+       }
+       return false
+}
+
+// hasNil reports whether a type includes the nil value.
+func hasNil(typ Type) bool {
+       switch t := optype(typ.Under()).(type) {
+       case *Basic:
+               return t.kind == UnsafePointer
+       case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
+               return true
+       case *Sum:
+               return t.is(hasNil)
+       }
+       return false
+}
+
+// identical reports whether x and y are identical types.
+// Receivers of Signature types are ignored.
+func (check *Checker) identical(x, y Type) bool {
+       return check.identical0(x, y, true, nil)
+}
+
+// identicalIgnoreTags reports whether x and y are identical types if tags are ignored.
+// Receivers of Signature types are ignored.
+func (check *Checker) identicalIgnoreTags(x, y Type) bool {
+       return check.identical0(x, y, false, nil)
+}
+
+// An ifacePair is a node in a stack of interface type pairs compared for identity.
+type ifacePair struct {
+       x, y *Interface
+       prev *ifacePair
+}
+
+func (p *ifacePair) identical(q *ifacePair) bool {
+       return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
+}
+
+// For changes to this code the corresponding changes should be made to unifier.nify.
+func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
+       // types must be expanded for comparison
+       x = expandf(x)
+       y = expandf(y)
+
+       if x == y {
+               return true
+       }
+
+       switch x := x.(type) {
+       case *Basic:
+               // Basic types are singletons except for the rune and byte
+               // aliases, thus we cannot solely rely on the x == y check
+               // above. See also comment in TypeName.IsAlias.
+               if y, ok := y.(*Basic); ok {
+                       return x.kind == y.kind
+               }
+
+       case *Array:
+               // Two array types are identical if they have identical element types
+               // and the same array length.
+               if y, ok := y.(*Array); ok {
+                       // If one or both array lengths are unknown (< 0) due to some error,
+                       // assume they are the same to avoid spurious follow-on errors.
+                       return (x.len < 0 || y.len < 0 || x.len == y.len) && check.identical0(x.elem, y.elem, cmpTags, p)
+               }
+
+       case *Slice:
+               // Two slice types are identical if they have identical element types.
+               if y, ok := y.(*Slice); ok {
+                       return check.identical0(x.elem, y.elem, cmpTags, p)
+               }
+
+       case *Struct:
+               // Two struct types are identical if they have the same sequence of fields,
+               // and if corresponding fields have the same names, and identical types,
+               // and identical tags. Two embedded fields are considered to have the same
+               // name. Lower-case field names from different packages are always different.
+               if y, ok := y.(*Struct); ok {
+                       if x.NumFields() == y.NumFields() {
+                               for i, f := range x.fields {
+                                       g := y.fields[i]
+                                       if f.embedded != g.embedded ||
+                                               cmpTags && x.Tag(i) != y.Tag(i) ||
+                                               !f.sameId(g.pkg, g.name) ||
+                                               !check.identical0(f.typ, g.typ, cmpTags, p) {
+                                               return false
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *Pointer:
+               // Two pointer types are identical if they have identical base types.
+               if y, ok := y.(*Pointer); ok {
+                       return check.identical0(x.base, y.base, cmpTags, p)
+               }
+
+       case *Tuple:
+               // Two tuples types are identical if they have the same number of elements
+               // and corresponding elements have identical types.
+               if y, ok := y.(*Tuple); ok {
+                       if x.Len() == y.Len() {
+                               if x != nil {
+                                       for i, v := range x.vars {
+                                               w := y.vars[i]
+                                               if !check.identical0(v.typ, w.typ, cmpTags, p) {
+                                                       return false
+                                               }
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *Signature:
+               // Two function types are identical if they have the same number of parameters
+               // and result values, corresponding parameter and result types are identical,
+               // and either both functions are variadic or neither is. Parameter and result
+               // names are not required to match.
+               // Generic functions must also have matching type parameter lists, but for the
+               // parameter names.
+               if y, ok := y.(*Signature); ok {
+                       return x.variadic == y.variadic &&
+                               check.identicalTParams(x.tparams, y.tparams, cmpTags, p) &&
+                               check.identical0(x.params, y.params, cmpTags, p) &&
+                               check.identical0(x.results, y.results, cmpTags, p)
+               }
+
+       case *Sum:
+               // Two sum types are identical if they contain the same types.
+               // (Sum types always consist of at least two types. Also, the
+               // the set (list) of types in a sum type consists of unique
+               // types - each type appears exactly once. Thus, two sum types
+               // must contain the same number of types to have chance of
+               // being equal.
+               if y, ok := y.(*Sum); ok && len(x.types) == len(y.types) {
+                       // Every type in x.types must be in y.types.
+                       // Quadratic algorithm, but probably good enough for now.
+                       // TODO(gri) we need a fast quick type ID/hash for all types.
+               L:
+                       for _, x := range x.types {
+                               for _, y := range y.types {
+                                       if Identical(x, y) {
+                                               continue L // x is in y.types
+                                       }
+                               }
+                               return false // x is not in y.types
+                       }
+                       return true
+               }
+
+       case *Interface:
+               // Two interface types are identical if they have the same set of methods with
+               // the same names and identical function types. Lower-case method names from
+               // different packages are always different. The order of the methods is irrelevant.
+               if y, ok := y.(*Interface); ok {
+                       // If identical0 is called (indirectly) via an external API entry point
+                       // (such as Identical, IdenticalIgnoreTags, etc.), check is nil. But in
+                       // that case, interfaces are expected to be complete and lazy completion
+                       // here is not needed.
+                       if check != nil {
+                               check.completeInterface(nopos, x)
+                               check.completeInterface(nopos, y)
+                       }
+                       a := x.allMethods
+                       b := y.allMethods
+                       if len(a) == len(b) {
+                               // Interface types are the only types where cycles can occur
+                               // that are not "terminated" via named types; and such cycles
+                               // can only be created via method parameter types that are
+                               // anonymous interfaces (directly or indirectly) embedding
+                               // the current interface. Example:
+                               //
+                               //    type T interface {
+                               //        m() interface{T}
+                               //    }
+                               //
+                               // If two such (differently named) interfaces are compared,
+                               // endless recursion occurs if the cycle is not detected.
+                               //
+                               // If x and y were compared before, they must be equal
+                               // (if they were not, the recursion would have stopped);
+                               // search the ifacePair stack for the same pair.
+                               //
+                               // This is a quadratic algorithm, but in practice these stacks
+                               // are extremely short (bounded by the nesting depth of interface
+                               // type declarations that recur via parameter types, an extremely
+                               // rare occurrence). An alternative implementation might use a
+                               // "visited" map, but that is probably less efficient overall.
+                               q := &ifacePair{x, y, p}
+                               for p != nil {
+                                       if p.identical(q) {
+                                               return true // same pair was compared before
+                                       }
+                                       p = p.prev
+                               }
+                               if debug {
+                                       assert(sort.IsSorted(byUniqueMethodName(a)))
+                                       assert(sort.IsSorted(byUniqueMethodName(b)))
+                               }
+                               for i, f := range a {
+                                       g := b[i]
+                                       if f.Id() != g.Id() || !check.identical0(f.typ, g.typ, cmpTags, q) {
+                                               return false
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *Map:
+               // Two map types are identical if they have identical key and value types.
+               if y, ok := y.(*Map); ok {
+                       return check.identical0(x.key, y.key, cmpTags, p) && check.identical0(x.elem, y.elem, cmpTags, p)
+               }
+
+       case *Chan:
+               // Two channel types are identical if they have identical value types
+               // and the same direction.
+               if y, ok := y.(*Chan); ok {
+                       return x.dir == y.dir && check.identical0(x.elem, y.elem, cmpTags, p)
+               }
+
+       case *Named:
+               // Two named types are identical if their type names originate
+               // in the same type declaration.
+               if y, ok := y.(*Named); ok {
+                       // TODO(gri) Why is x == y not sufficient? And if it is,
+                       //           we can just return false here because x == y
+                       //           is caught in the very beginning of this function.
+                       return x.obj == y.obj
+               }
+
+       case *TypeParam:
+               // nothing to do (x and y being equal is caught in the very beginning of this function)
+
+       // case *instance:
+       //      unreachable since types are expanded
+
+       case *bottom, *top:
+               // Either both types are theBottom, or both are theTop in which
+               // case the initial x == y check will have caught them. Otherwise
+               // they are not identical.
+
+       case nil:
+               // avoid a crash in case of nil type
+
+       default:
+               unreachable()
+       }
+
+       return false
+}
+
+func (check *Checker) identicalTParams(x, y []*TypeName, cmpTags bool, p *ifacePair) bool {
+       if len(x) != len(y) {
+               return false
+       }
+       for i, x := range x {
+               y := y[i]
+               if !check.identical0(x.typ.(*TypeParam).bound, y.typ.(*TypeParam).bound, cmpTags, p) {
+                       return false
+               }
+       }
+       return true
+}
+
+// Default returns the default "typed" type for an "untyped" type;
+// it returns the incoming type for all other types. The default type
+// for untyped nil is untyped nil.
+//
+func Default(typ Type) Type {
+       if t, ok := typ.(*Basic); ok {
+               switch t.kind {
+               case UntypedBool:
+                       return Typ[Bool]
+               case UntypedInt:
+                       return Typ[Int]
+               case UntypedRune:
+                       return universeRune // use 'rune' name
+               case UntypedFloat:
+                       return Typ[Float64]
+               case UntypedComplex:
+                       return Typ[Complex128]
+               case UntypedString:
+                       return Typ[String]
+               }
+       }
+       return typ
+}
diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go
new file mode 100644 (file)
index 0000000..7ea9bde
--- /dev/null
@@ -0,0 +1,733 @@
+// UNREVIEWED
+// Copyright 2013 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 (
+       "cmd/compile/internal/syntax"
+       "fmt"
+       "go/constant"
+       "sort"
+       "strconv"
+       "strings"
+       "unicode"
+)
+
+// A declInfo describes a package-level const, type, var, or func declaration.
+type declInfo struct {
+       file      *Scope           // scope of file containing this declaration
+       lhs       []*Var           // lhs of n:1 variable declarations, or nil
+       vtyp      syntax.Expr      // type, or nil (for const and var declarations only)
+       init      syntax.Expr      // init/orig expression, or nil (for const and var declarations only)
+       inherited bool             // if set, the init expression is inherited from a previous constant declaration
+       tdecl     *syntax.TypeDecl // type declaration, or nil
+       fdecl     *syntax.FuncDecl // func declaration, or nil
+
+       // The deps field tracks initialization expression dependencies.
+       deps map[Object]bool // lazily initialized
+}
+
+// hasInitializer reports whether the declared object has an initialization
+// expression or function body.
+func (d *declInfo) hasInitializer() bool {
+       return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil
+}
+
+// addDep adds obj to the set of objects d's init expression depends on.
+func (d *declInfo) addDep(obj Object) {
+       m := d.deps
+       if m == nil {
+               m = make(map[Object]bool)
+               d.deps = m
+       }
+       m[obj] = true
+}
+
+// arity checks that the lhs and rhs of a const or var decl
+// have a matching number of names and initialization values.
+// If inherited is set, the initialization values are from
+// another (constant) declaration.
+func (check *Checker) arity(pos syntax.Pos, names []*syntax.Name, inits []syntax.Expr, constDecl, inherited bool) {
+       l := len(names)
+       r := len(inits)
+
+       switch {
+       case l < r:
+               n := inits[l]
+               if inherited {
+                       check.errorf(pos, "extra init expr at %s", n.Pos())
+               } else {
+                       check.errorf(n, "extra init expr %s", n)
+               }
+       case l > r && (constDecl || r != 1): // if r == 1 it may be a multi-valued function and we can't say anything yet
+               n := names[r]
+               check.errorf(n, "missing init expr for %s", n.Value)
+       }
+}
+
+func validatedImportPath(path string) (string, error) {
+       s, err := strconv.Unquote(path)
+       if err != nil {
+               return "", err
+       }
+       if s == "" {
+               return "", fmt.Errorf("empty string")
+       }
+       const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+       for _, r := range s {
+               if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+                       return s, fmt.Errorf("invalid character %#U", r)
+               }
+       }
+       return s, nil
+}
+
+// declarePkgObj declares obj in the package scope, records its ident -> obj mapping,
+// and updates check.objMap. The object must not be a function or method.
+func (check *Checker) declarePkgObj(ident *syntax.Name, obj Object, d *declInfo) {
+       assert(ident.Value == obj.Name())
+
+       // spec: "A package-scope or file-scope identifier with name init
+       // may only be declared to be a function with this (func()) signature."
+       if ident.Value == "init" {
+               check.errorf(ident, "cannot declare init - must be func")
+               return
+       }
+
+       // spec: "The main package must have package name main and declare
+       // a function main that takes no arguments and returns no value."
+       if ident.Value == "main" && check.pkg.name == "main" {
+               check.errorf(ident, "cannot declare main - must be func")
+               return
+       }
+
+       check.declare(check.pkg.scope, ident, obj, nopos)
+       check.objMap[obj] = d
+       obj.setOrder(uint32(len(check.objMap)))
+}
+
+// filename returns a filename suitable for debugging output.
+func (check *Checker) filename(fileNo int) string {
+       file := check.files[fileNo]
+       if pos := file.Pos(); pos.IsKnown() {
+               // return check.fset.File(pos).Name()
+               // TODO(gri) do we need the actual file name here?
+               return pos.RelFilename()
+       }
+       return fmt.Sprintf("file[%d]", fileNo)
+}
+
+func (check *Checker) importPackage(pos syntax.Pos, path, dir string) *Package {
+       // If we already have a package for the given (path, dir)
+       // pair, use it instead of doing a full import.
+       // Checker.impMap only caches packages that are marked Complete
+       // or fake (dummy packages for failed imports). Incomplete but
+       // non-fake packages do require an import to complete them.
+       key := importKey{path, dir}
+       imp := check.impMap[key]
+       if imp != nil {
+               return imp
+       }
+
+       // no package yet => import it
+       if path == "C" && (check.conf.FakeImportC || check.conf.go115UsesCgo) {
+               imp = NewPackage("C", "C")
+               imp.fake = true // package scope is not populated
+               imp.cgo = check.conf.go115UsesCgo
+       } else {
+               // ordinary import
+               var err error
+               if importer := check.conf.Importer; importer == nil {
+                       err = fmt.Errorf("Config.Importer not installed")
+               } else if importerFrom, ok := importer.(ImporterFrom); ok {
+                       imp, err = importerFrom.ImportFrom(path, dir, 0)
+                       if imp == nil && err == nil {
+                               err = fmt.Errorf("Config.Importer.ImportFrom(%s, %s, 0) returned nil but no error", path, dir)
+                       }
+               } else {
+                       imp, err = importer.Import(path)
+                       if imp == nil && err == nil {
+                               err = fmt.Errorf("Config.Importer.Import(%s) returned nil but no error", path)
+                       }
+               }
+               // make sure we have a valid package name
+               // (errors here can only happen through manipulation of packages after creation)
+               if err == nil && imp != nil && (imp.name == "_" || imp.name == "") {
+                       err = fmt.Errorf("invalid package name: %q", imp.name)
+                       imp = nil // create fake package below
+               }
+               if err != nil {
+                       check.errorf(pos, "could not import %s (%s)", path, err)
+                       if imp == nil {
+                               // create a new fake package
+                               // come up with a sensible package name (heuristic)
+                               name := path
+                               if i := len(name); i > 0 && name[i-1] == '/' {
+                                       name = name[:i-1]
+                               }
+                               if i := strings.LastIndex(name, "/"); i >= 0 {
+                                       name = name[i+1:]
+                               }
+                               imp = NewPackage(path, name)
+                       }
+                       // continue to use the package as best as we can
+                       imp.fake = true // avoid follow-up lookup failures
+               }
+       }
+
+       // package should be complete or marked fake, but be cautious
+       if imp.complete || imp.fake {
+               check.impMap[key] = imp
+               check.pkgCnt[imp.name]++
+               return imp
+       }
+
+       // something went wrong (importer may have returned incomplete package without error)
+       return nil
+}
+
+// collectObjects collects all file and package objects and inserts them
+// into their respective scopes. It also performs imports and associates
+// methods with receiver base type names.
+func (check *Checker) collectObjects() {
+       pkg := check.pkg
+
+       // pkgImports is the set of packages already imported by any package file seen
+       // so far. Used to avoid duplicate entries in pkg.imports. Allocate and populate
+       // it (pkg.imports may not be empty if we are checking test files incrementally).
+       // Note that pkgImports is keyed by package (and thus package path), not by an
+       // importKey value. Two different importKey values may map to the same package
+       // which is why we cannot use the check.impMap here.
+       var pkgImports = make(map[*Package]bool)
+       for _, imp := range pkg.imports {
+               pkgImports[imp] = true
+       }
+
+       type methodInfo struct {
+               obj  *Func        // method
+               ptr  bool         // true if pointer receiver
+               recv *syntax.Name // receiver type name
+       }
+       var methods []methodInfo // collected methods with valid receivers and non-blank _ names
+       var fileScopes []*Scope
+       for fileNo, file := range check.files {
+               // The package identifier denotes the current package,
+               // but there is no corresponding package object.
+               check.recordDef(file.PkgName, nil)
+
+               fileScope := NewScope(check.pkg.scope, startPos(file), endPos(file), check.filename(fileNo))
+               fileScopes = append(fileScopes, fileScope)
+               check.recordScope(file, fileScope)
+
+               // determine file directory, necessary to resolve imports
+               // FileName may be "" (typically for tests) in which case
+               // we get "." as the directory which is what we would want.
+               fileDir := dir(file.PkgName.Pos().RelFilename()) // TODO(gri) should this be filename?
+
+               first := -1                // index of first ConstDecl in the current group, or -1
+               var last *syntax.ConstDecl // last ConstDecl with init expressions, or nil
+               for index, decl := range file.DeclList {
+                       if _, ok := decl.(*syntax.ConstDecl); !ok {
+                               first = -1 // we're not in a constant declaration
+                       }
+
+                       switch s := decl.(type) {
+                       case *syntax.ImportDecl:
+                               // import package
+                               if s.Path == nil || s.Path.Bad {
+                                       continue // error reported during parsing
+                               }
+                               path, err := validatedImportPath(s.Path.Value)
+                               if err != nil {
+                                       check.errorf(s.Path, "invalid import path (%s)", err)
+                                       continue
+                               }
+
+                               imp := check.importPackage(s.Path.Pos(), path, fileDir)
+                               if imp == nil {
+                                       continue
+                               }
+
+                               // add package to list of explicit imports
+                               // (this functionality is provided as a convenience
+                               // for clients; it is not needed for type-checking)
+                               if !pkgImports[imp] {
+                                       pkgImports[imp] = true
+                                       pkg.imports = append(pkg.imports, imp)
+                               }
+
+                               // local name overrides imported package name
+                               name := imp.name
+                               if s.LocalPkgName != nil {
+                                       name = s.LocalPkgName.Value
+                                       if path == "C" {
+                                               // match cmd/compile (not prescribed by spec)
+                                               check.errorf(s.LocalPkgName, `cannot rename import "C"`)
+                                               continue
+                                       }
+                                       if name == "init" {
+                                               check.errorf(s.LocalPkgName, "cannot declare init - must be func")
+                                               continue
+                                       }
+                               }
+
+                               obj := NewPkgName(s.Pos(), pkg, name, imp)
+                               if s.LocalPkgName != nil {
+                                       // in a dot-import, the dot represents the package
+                                       check.recordDef(s.LocalPkgName, obj)
+                               } else {
+                                       check.recordImplicit(s, obj)
+                               }
+
+                               if path == "C" {
+                                       // match cmd/compile (not prescribed by spec)
+                                       obj.used = true
+                               }
+
+                               // add import to file scope
+                               if name == "." {
+                                       // merge imported scope with file scope
+                                       for _, obj := range imp.scope.elems {
+                                               // A package scope may contain non-exported objects,
+                                               // do not import them!
+                                               if obj.Exported() {
+                                                       // declare dot-imported object
+                                                       // (Do not use check.declare because it modifies the object
+                                                       // via Object.setScopePos, which leads to a race condition;
+                                                       // the object may be imported into more than one file scope
+                                                       // concurrently. See issue #32154.)
+                                                       if alt := fileScope.Insert(obj); alt != nil {
+                                                               check.errorf(s.LocalPkgName, "%s redeclared in this block", obj.Name())
+                                                               check.reportAltDecl(alt)
+                                                       }
+                                               }
+                                       }
+                                       // add position to set of dot-import positions for this file
+                                       // (this is only needed for "imported but not used" errors)
+                                       check.addUnusedDotImport(fileScope, imp, s.Pos())
+                               } else {
+                                       // declare imported package object in file scope
+                                       // (no need to provide s.LocalPkgName since we called check.recordDef earlier)
+                                       check.declare(fileScope, nil, obj, nopos)
+                               }
+
+                       case *syntax.ConstDecl:
+                               // iota is the index of the current constDecl within the group
+                               if first < 0 || file.DeclList[index-1].(*syntax.ConstDecl).Group != s.Group {
+                                       first = index
+                                       last = nil
+                               }
+                               iota := constant.MakeInt64(int64(index - first))
+
+                               // determine which initialization expressions to use
+                               inherited := true
+                               switch {
+                               case s.Type != nil || s.Values != nil:
+                                       last = s
+                                       inherited = false
+                               case last == nil:
+                                       last = new(syntax.ConstDecl) // make sure last exists
+                                       inherited = false
+                               }
+
+                               // declare all constants
+                               values := unpackExpr(last.Values)
+                               for i, name := range s.NameList {
+                                       obj := NewConst(name.Pos(), pkg, name.Value, nil, iota)
+
+                                       var init syntax.Expr
+                                       if i < len(values) {
+                                               init = values[i]
+                                       }
+
+                                       d := &declInfo{file: fileScope, vtyp: last.Type, init: init, inherited: inherited}
+                                       check.declarePkgObj(name, obj, d)
+                               }
+
+                               // Constants must always have init values.
+                               check.arity(s.Pos(), s.NameList, values, true, inherited)
+
+                       case *syntax.VarDecl:
+                               lhs := make([]*Var, len(s.NameList))
+                               // If there's exactly one rhs initializer, use
+                               // the same declInfo d1 for all lhs variables
+                               // so that each lhs variable depends on the same
+                               // rhs initializer (n:1 var declaration).
+                               var d1 *declInfo
+                               if _, ok := s.Values.(*syntax.ListExpr); !ok {
+                                       // The lhs elements are only set up after the for loop below,
+                                       // but that's ok because declarePkgObj only collects the declInfo
+                                       // for a later phase.
+                                       d1 = &declInfo{file: fileScope, lhs: lhs, vtyp: s.Type, init: s.Values}
+                               }
+
+                               // declare all variables
+                               values := unpackExpr(s.Values)
+                               for i, name := range s.NameList {
+                                       obj := NewVar(name.Pos(), pkg, name.Value, nil)
+                                       lhs[i] = obj
+
+                                       d := d1
+                                       if d == nil {
+                                               // individual assignments
+                                               var init syntax.Expr
+                                               if i < len(values) {
+                                                       init = values[i]
+                                               }
+                                               d = &declInfo{file: fileScope, vtyp: s.Type, init: init}
+                                       }
+
+                                       check.declarePkgObj(name, obj, d)
+                               }
+
+                               // If we have no type, we must have values.
+                               if s.Type == nil || values != nil {
+                                       check.arity(s.Pos(), s.NameList, values, false, false)
+                               }
+
+                       case *syntax.TypeDecl:
+                               obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil)
+                               check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s})
+
+                       case *syntax.FuncDecl:
+                               d := s // TODO(gri) get rid of this
+                               name := d.Name.Value
+                               obj := NewFunc(d.Name.Pos(), pkg, name, nil)
+                               if d.Recv == nil {
+                                       // regular function
+                                       if name == "init" || name == "main" && pkg.name == "main" {
+                                               if d.TParamList != nil {
+                                                       check.softErrorf(d, "func %s must have no type parameters", name)
+                                               }
+                                               if t := d.Type; len(t.ParamList) != 0 || len(t.ResultList) != 0 {
+                                                       check.softErrorf(d, "func %s must have no arguments and no return values", name)
+                                               }
+                                       }
+                                       // don't declare init functions in the package scope - they are invisible
+                                       if name == "init" {
+                                               obj.parent = pkg.scope
+                                               check.recordDef(d.Name, obj)
+                                               // init functions must have a body
+                                               if d.Body == nil {
+                                                       // TODO(gri) make this error message consistent with the others above
+                                                       check.softErrorf(obj.pos, "missing function body")
+                                               }
+                                       } else {
+                                               check.declare(pkg.scope, d.Name, obj, nopos)
+                                       }
+                               } else {
+                                       // method
+                                       // d.Recv != nil
+                                       if !methodTypeParamsOk && len(d.TParamList) != 0 {
+                                               //check.invalidASTf(d.TParamList.Pos(), "method must have no type parameters")
+                                               check.invalidASTf(d, "method must have no type parameters")
+                                       }
+                                       ptr, recv, _ := check.unpackRecv(d.Recv.Type, false)
+                                       // (Methods with invalid receiver cannot be associated to a type, and
+                                       // methods with blank _ names are never found; no need to collect any
+                                       // of them. They will still be type-checked with all the other functions.)
+                                       if recv != nil && name != "_" {
+                                               methods = append(methods, methodInfo{obj, ptr, recv})
+                                       }
+                                       check.recordDef(d.Name, obj)
+                               }
+                               info := &declInfo{file: fileScope, fdecl: d}
+                               // Methods are not package-level objects but we still track them in the
+                               // object map so that we can handle them like regular functions (if the
+                               // receiver is invalid); also we need their fdecl info when associating
+                               // them with their receiver base type, below.
+                               check.objMap[obj] = info
+                               obj.setOrder(uint32(len(check.objMap)))
+
+                       default:
+                               check.invalidASTf(s, "unknown syntax.Decl node %T", s)
+                       }
+               }
+       }
+
+       // verify that objects in package and file scopes have different names
+       for _, scope := range fileScopes {
+               for _, obj := range scope.elems {
+                       if alt := pkg.scope.Lookup(obj.Name()); alt != nil {
+                               if pkg, ok := obj.(*PkgName); ok {
+                                       check.errorf(alt, "%s already declared through import of %s", alt.Name(), pkg.Imported())
+                                       check.reportAltDecl(pkg)
+                               } else {
+                                       check.errorf(alt, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
+                                       // TODO(gri) dot-imported objects don't have a position; reportAltDecl won't print anything
+                                       check.reportAltDecl(obj)
+                               }
+                       }
+               }
+       }
+
+       // Now that we have all package scope objects and all methods,
+       // associate methods with receiver base type name where possible.
+       // Ignore methods that have an invalid receiver. They will be
+       // type-checked later, with regular functions.
+       if methods != nil {
+               check.methods = make(map[*TypeName][]*Func)
+               for i := range methods {
+                       m := &methods[i]
+                       // Determine the receiver base type and associate m with it.
+                       ptr, base := check.resolveBaseTypeName(m.ptr, m.recv)
+                       if base != nil {
+                               m.obj.hasPtrRecv = ptr
+                               check.methods[base] = append(check.methods[base], m.obj)
+                       }
+               }
+       }
+}
+
+// unpackRecv unpacks a receiver type and returns its components: ptr indicates whether
+// rtyp is a pointer receiver, rname is the receiver type name, and tparams are its
+// type parameters, if any. The type parameters are only unpacked if unpackParams is
+// set. If rname is nil, the receiver is unusable (i.e., the source has a bug which we
+// cannot easily work around).
+func (check *Checker) unpackRecv(rtyp syntax.Expr, unpackParams bool) (ptr bool, rname *syntax.Name, tparams []*syntax.Name) {
+L: // unpack receiver type
+       // This accepts invalid receivers such as ***T and does not
+       // work for other invalid receivers, but we don't care. The
+       // validity of receiver expressions is checked elsewhere.
+       for {
+               switch t := rtyp.(type) {
+               case *syntax.ParenExpr:
+                       rtyp = t.X
+               // case *ast.StarExpr:
+               //      ptr = true
+               //      rtyp = t.X
+               case *syntax.Operation:
+                       if t.Op != syntax.Mul || t.Y != nil {
+                               break
+                       }
+                       ptr = true
+                       rtyp = t.X
+               default:
+                       break L
+               }
+       }
+
+       // unpack type parameters, if any
+       if ptyp, _ := rtyp.(*syntax.IndexExpr); ptyp != nil {
+               rtyp = ptyp.X
+               if unpackParams {
+                       for _, arg := range unpackExpr(ptyp.Index) {
+                               var par *syntax.Name
+                               switch arg := arg.(type) {
+                               case *syntax.Name:
+                                       par = arg
+                               case *syntax.BadExpr:
+                                       // ignore - error already reported by parser
+                               case nil:
+                                       check.invalidASTf(ptyp, "parameterized receiver contains nil parameters")
+                               default:
+                                       check.errorf(arg, "receiver type parameter %s must be an identifier", arg)
+                               }
+                               if par == nil {
+                                       par = syntax.NewName(arg.Pos(), "_")
+                               }
+                               tparams = append(tparams, par)
+                       }
+
+               }
+       }
+
+       // unpack receiver name
+       if name, _ := rtyp.(*syntax.Name); name != nil {
+               rname = name
+       }
+
+       return
+}
+
+// resolveBaseTypeName returns the non-alias base type name for typ, and whether
+// there was a pointer indirection to get to it. The base type name must be declared
+// in package scope, and there can be at most one pointer indirection. If no such type
+// name exists, the returned base is nil.
+func (check *Checker) resolveBaseTypeName(seenPtr bool, typ syntax.Expr) (ptr bool, base *TypeName) {
+       // Algorithm: Starting from a type expression, which may be a name,
+       // we follow that type through alias declarations until we reach a
+       // non-alias type name. If we encounter anything but pointer types or
+       // parentheses we're done. If we encounter more than one pointer type
+       // we're done.
+       ptr = seenPtr
+       var seen map[*TypeName]bool
+       for {
+               typ = unparen(typ)
+
+               // check if we have a pointer type
+               // if pexpr, _ := typ.(*ast.StarExpr); pexpr != nil {
+               if pexpr, _ := typ.(*syntax.Operation); pexpr != nil && pexpr.Op == syntax.Mul && pexpr.Y == nil {
+                       // if we've already seen a pointer, we're done
+                       if ptr {
+                               return false, nil
+                       }
+                       ptr = true
+                       typ = unparen(pexpr.X) // continue with pointer base type
+               }
+
+               // typ must be a name
+               name, _ := typ.(*syntax.Name)
+               if name == nil {
+                       return false, nil
+               }
+
+               // name must denote an object found in the current package scope
+               // (note that dot-imported objects are not in the package scope!)
+               obj := check.pkg.scope.Lookup(name.Value)
+               if obj == nil {
+                       return false, nil
+               }
+
+               // the object must be a type name...
+               tname, _ := obj.(*TypeName)
+               if tname == nil {
+                       return false, nil
+               }
+
+               // ... which we have not seen before
+               if seen[tname] {
+                       return false, nil
+               }
+
+               // we're done if tdecl defined tname as a new type
+               // (rather than an alias)
+               tdecl := check.objMap[tname].tdecl // must exist for objects in package scope
+               if !tdecl.Alias {
+                       return ptr, tname
+               }
+
+               // otherwise, continue resolving
+               typ = tdecl.Type
+               if seen == nil {
+                       seen = make(map[*TypeName]bool)
+               }
+               seen[tname] = true
+       }
+}
+
+// packageObjects typechecks all package objects, but not function bodies.
+func (check *Checker) packageObjects() {
+       // process package objects in source order for reproducible results
+       objList := make([]Object, len(check.objMap))
+       i := 0
+       for obj := range check.objMap {
+               objList[i] = obj
+               i++
+       }
+       sort.Sort(inSourceOrder(objList))
+
+       // add new methods to already type-checked types (from a prior Checker.Files call)
+       for _, obj := range objList {
+               if obj, _ := obj.(*TypeName); obj != nil && obj.typ != nil {
+                       check.collectMethods(obj)
+               }
+       }
+
+       // We process non-alias declarations first, in order to avoid situations where
+       // the type of an alias declaration is needed before it is available. In general
+       // this is still not enough, as it is possible to create sufficiently convoluted
+       // recursive type definitions that will cause a type alias to be needed before it
+       // is available (see issue #25838 for examples).
+       // As an aside, the cmd/compiler suffers from the same problem (#25838).
+       var aliasList []*TypeName
+       // phase 1
+       for _, obj := range objList {
+               // If we have a type alias, collect it for the 2nd phase.
+               if tname, _ := obj.(*TypeName); tname != nil && check.objMap[tname].tdecl.Alias {
+                       aliasList = append(aliasList, tname)
+                       continue
+               }
+
+               check.objDecl(obj, nil)
+       }
+       // phase 2
+       for _, obj := range aliasList {
+               check.objDecl(obj, nil)
+       }
+
+       // At this point we may have a non-empty check.methods map; this means that not all
+       // entries were deleted at the end of typeDecl because the respective receiver base
+       // types were not found. In that case, an error was reported when declaring those
+       // methods. We can now safely discard this map.
+       check.methods = nil
+}
+
+// inSourceOrder implements the sort.Sort interface.
+type inSourceOrder []Object
+
+func (a inSourceOrder) Len() int           { return len(a) }
+func (a inSourceOrder) Less(i, j int) bool { return a[i].order() < a[j].order() }
+func (a inSourceOrder) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+// unusedImports checks for unused imports.
+func (check *Checker) unusedImports() {
+       // if function bodies are not checked, packages' uses are likely missing - don't check
+       if check.conf.IgnoreFuncBodies {
+               return
+       }
+
+       // spec: "It is illegal (...) to directly import a package without referring to
+       // any of its exported identifiers. To import a package solely for its side-effects
+       // (initialization), use the blank identifier as explicit package name."
+
+       // check use of regular imported packages
+       for _, scope := range check.pkg.scope.children /* file scopes */ {
+               for _, obj := range scope.elems {
+                       if obj, ok := obj.(*PkgName); ok {
+                               // Unused "blank imports" are automatically ignored
+                               // since _ identifiers are not entered into scopes.
+                               if !obj.used {
+                                       path := obj.imported.path
+                                       base := pkgName(path)
+                                       if obj.name == base {
+                                               if check.conf.CompilerErrorMessages {
+                                                       check.softErrorf(obj.pos, "%q imported and not used", path)
+                                               } else {
+                                                       check.softErrorf(obj.pos, "%q imported but not used", path)
+                                               }
+                                       } else {
+                                               if check.conf.CompilerErrorMessages {
+                                                       check.softErrorf(obj.pos, "%q imported and not used as %s", path, obj.name)
+                                               } else {
+                                                       check.softErrorf(obj.pos, "%q imported but not used as %s", path, obj.name)
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // check use of dot-imported packages
+       for _, unusedDotImports := range check.unusedDotImports {
+               for pkg, pos := range unusedDotImports {
+                       if check.conf.CompilerErrorMessages {
+                               check.softErrorf(pos, "%q imported and not used", pkg.path)
+                       } else {
+                               check.softErrorf(pos, "%q imported but not used", pkg.path)
+                       }
+               }
+       }
+}
+
+// pkgName returns the package name (last element) of an import path.
+func pkgName(path string) string {
+       if i := strings.LastIndex(path, "/"); i >= 0 {
+               path = path[i+1:]
+       }
+       return path
+}
+
+// dir makes a good-faith attempt to return the directory
+// portion of path. If path is empty, the result is ".".
+// (Per the go/build package dependency tests, we cannot import
+// path/filepath and simply use filepath.Dir.)
+func dir(path string) string {
+       if i := strings.LastIndexAny(path, `/\`); i > 0 {
+               return path[:i]
+       }
+       // i <= 0
+       return "."
+}
diff --git a/src/cmd/compile/internal/types2/resolver_test.go b/src/cmd/compile/internal/types2/resolver_test.go
new file mode 100644 (file)
index 0000000..cdfdba6
--- /dev/null
@@ -0,0 +1,223 @@
+// UNREVIEWED
+// Copyright 2011 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/syntax"
+       "fmt"
+       "internal/testenv"
+       "sort"
+       "testing"
+
+       . "cmd/compile/internal/types2"
+)
+
+type resolveTestImporter struct {
+       importer ImporterFrom
+       imported map[string]bool
+}
+
+func (imp *resolveTestImporter) Import(string) (*Package, error) {
+       panic("should not be called")
+}
+
+func (imp *resolveTestImporter) ImportFrom(path, srcDir string, mode ImportMode) (*Package, error) {
+       if mode != 0 {
+               panic("mode must be 0")
+       }
+       if imp.importer == nil {
+               imp.importer = defaultImporter().(ImporterFrom)
+               imp.imported = make(map[string]bool)
+       }
+       pkg, err := imp.importer.ImportFrom(path, srcDir, mode)
+       if err != nil {
+               return nil, err
+       }
+       imp.imported[path] = true
+       return pkg, nil
+}
+
+func TestResolveIdents(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       sources := []string{
+               `
+               package p
+               import "fmt"
+               import "math"
+               const pi = math.Pi
+               func sin(x float64) float64 {
+                       return math.Sin(x)
+               }
+               var Println = fmt.Println
+               `,
+               `
+               package p
+               import "fmt"
+               type errorStringer struct { fmt.Stringer; error }
+               func f() string {
+                       _ = "foo"
+                       return fmt.Sprintf("%d", g())
+               }
+               func g() (x int) { return }
+               `,
+               `
+               package p
+               import . "go/parser"
+               import "sync"
+               func h() Mode { return ImportsOnly }
+               var _, x int = 1, 2
+               func init() {}
+               type T struct{ *sync.Mutex; a, b, c int}
+               type I interface{ m() }
+               var _ = T{a: 1, b: 2, c: 3}
+               func (_ T) m() {}
+               func (T) _() {}
+               var i I
+               var _ = i.m
+               func _(s []int) { for i, x := range s { _, _ = i, x } }
+               func _(x interface{}) {
+                       switch x := x.(type) {
+                       case int:
+                               _ = x
+                       }
+                       switch {} // implicit 'true' tag
+               }
+               `,
+               `
+               package p
+               type S struct{}
+               func (T) _() {}
+               func (T) _() {}
+               `,
+               `
+               package p
+               func _() {
+               L0:
+               L1:
+                       goto L0
+                       for {
+                               goto L1
+                       }
+                       if true {
+                               goto L2
+                       }
+               L2:
+               }
+               `,
+       }
+
+       pkgnames := []string{
+               "fmt",
+               "math",
+       }
+
+       // parse package files
+       var files []*syntax.File
+       for i, src := range sources {
+               f, err := parseSrc(fmt.Sprintf("sources[%d]", i), src)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               files = append(files, f)
+       }
+
+       // resolve and type-check package AST
+       importer := new(resolveTestImporter)
+       conf := Config{Importer: importer}
+       uses := make(map[*syntax.Name]Object)
+       defs := make(map[*syntax.Name]Object)
+       _, err := conf.Check("testResolveIdents", files, &Info{Defs: defs, Uses: uses})
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // check that all packages were imported
+       for _, name := range pkgnames {
+               if !importer.imported[name] {
+                       t.Errorf("package %s not imported", name)
+               }
+       }
+
+       // check that qualified identifiers are resolved
+       for _, f := range files {
+               Walk(f, func(n syntax.Node) bool {
+                       if s, ok := n.(*syntax.SelectorExpr); ok {
+                               if x, ok := s.X.(*syntax.Name); ok {
+                                       obj := uses[x]
+                                       if obj == nil {
+                                               t.Errorf("%s: unresolved qualified identifier %s", x.Pos(), x.Value)
+                                               return true
+                                       }
+                                       if _, ok := obj.(*PkgName); ok && uses[s.Sel] == nil {
+                                               t.Errorf("%s: unresolved selector %s", s.Sel.Pos(), s.Sel.Value)
+                                               return true
+                                       }
+                                       return true
+                               }
+                               return true
+                       }
+                       return false
+               })
+       }
+
+       for id, obj := range uses {
+               if obj == nil {
+                       t.Errorf("%s: Uses[%s] == nil", id.Pos(), id.Value)
+               }
+       }
+
+       // Check that each identifier in the source is found in uses or defs or both.
+       // We need the foundUses/Defs maps (rather then just deleting the found objects
+       // from the uses and defs maps) because Walk traverses shared nodes multiple
+       // times (e.g. types in field lists such as "a, b, c int").
+       foundUses := make(map[*syntax.Name]bool)
+       foundDefs := make(map[*syntax.Name]bool)
+       var both []string
+       for _, f := range files {
+               Walk(f, func(n syntax.Node) bool {
+                       if x, ok := n.(*syntax.Name); ok {
+                               var objects int
+                               if _, found := uses[x]; found {
+                                       objects |= 1
+                                       foundUses[x] = true
+                               }
+                               if _, found := defs[x]; found {
+                                       objects |= 2
+                                       foundDefs[x] = true
+                               }
+                               switch objects {
+                               case 0:
+                                       t.Errorf("%s: unresolved identifier %s", x.Pos(), x.Value)
+                               case 3:
+                                       both = append(both, x.Value)
+                               }
+                               return true
+                       }
+                       return false
+               })
+       }
+
+       // check the expected set of idents that are simultaneously uses and defs
+       sort.Strings(both)
+       if got, want := fmt.Sprint(both), "[Mutex Stringer error]"; got != want {
+               t.Errorf("simultaneous uses/defs = %s, want %s", got, want)
+       }
+
+       // any left-over identifiers didn't exist in the source
+       for x := range uses {
+               if !foundUses[x] {
+                       t.Errorf("%s: identifier %s not present in source", x.Pos(), x.Value)
+               }
+       }
+       for x := range defs {
+               if !foundDefs[x] {
+                       t.Errorf("%s: identifier %s not present in source", x.Pos(), x.Value)
+               }
+       }
+
+       // TODO(gri) add tests to check ImplicitObj callbacks
+}
diff --git a/src/cmd/compile/internal/types2/return.go b/src/cmd/compile/internal/types2/return.go
new file mode 100644 (file)
index 0000000..88234b1
--- /dev/null
@@ -0,0 +1,180 @@
+// UNREVIEWED
+// Copyright 2013 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.
+
+// This file implements isTerminating.
+
+package types2
+
+import (
+       "cmd/compile/internal/syntax"
+)
+
+// isTerminating reports if s is a terminating statement.
+// If s is labeled, label is the label name; otherwise s
+// is "".
+func (check *Checker) isTerminating(s syntax.Stmt, label string) bool {
+       switch s := s.(type) {
+       default:
+               unreachable()
+
+       case *syntax.DeclStmt, *syntax.EmptyStmt, *syntax.SendStmt,
+               *syntax.AssignStmt, *syntax.CallStmt:
+               // no chance
+
+       case *syntax.LabeledStmt:
+               return check.isTerminating(s.Stmt, s.Label.Value)
+
+       case *syntax.ExprStmt:
+               // calling the predeclared (possibly parenthesized) panic() function is terminating
+               if call, ok := unparen(s.X).(*syntax.CallExpr); ok && check.isPanic[call] {
+                       return true
+               }
+
+       case *syntax.ReturnStmt:
+               return true
+
+       case *syntax.BranchStmt:
+               if s.Tok == syntax.Goto || s.Tok == syntax.Fallthrough {
+                       return true
+               }
+
+       case *syntax.BlockStmt:
+               return check.isTerminatingList(s.List, "")
+
+       case *syntax.IfStmt:
+               if s.Else != nil &&
+                       check.isTerminating(s.Then, "") &&
+                       check.isTerminating(s.Else, "") {
+                       return true
+               }
+
+       case *syntax.SwitchStmt:
+               return check.isTerminatingSwitch(s.Body, label)
+
+       case *syntax.SelectStmt:
+               for _, cc := range s.Body {
+                       if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) {
+                               return false
+                       }
+
+               }
+               return true
+
+       case *syntax.ForStmt:
+               if s.Cond == nil && !hasBreak(s.Body, label, true) {
+                       return true
+               }
+       }
+
+       return false
+}
+
+func (check *Checker) isTerminatingList(list []syntax.Stmt, label string) bool {
+       // trailing empty statements are permitted - skip them
+       for i := len(list) - 1; i >= 0; i-- {
+               if _, ok := list[i].(*syntax.EmptyStmt); !ok {
+                       return check.isTerminating(list[i], label)
+               }
+       }
+       return false // all statements are empty
+}
+
+func (check *Checker) isTerminatingSwitch(body []*syntax.CaseClause, label string) bool {
+       hasDefault := false
+       for _, cc := range body {
+               if cc.Cases == nil {
+                       hasDefault = true
+               }
+               if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) {
+                       return false
+               }
+       }
+       return hasDefault
+}
+
+// TODO(gri) For nested breakable statements, the current implementation of hasBreak
+//          will traverse the same subtree repeatedly, once for each label. Replace
+//           with a single-pass label/break matching phase.
+
+// hasBreak reports if s is or contains a break statement
+// referring to the label-ed statement or implicit-ly the
+// closest outer breakable statement.
+func hasBreak(s syntax.Stmt, label string, implicit bool) bool {
+       switch s := s.(type) {
+       default:
+               unreachable()
+
+       case *syntax.DeclStmt, *syntax.EmptyStmt, *syntax.ExprStmt,
+               *syntax.SendStmt, *syntax.AssignStmt, *syntax.CallStmt,
+               *syntax.ReturnStmt:
+               // no chance
+
+       case *syntax.LabeledStmt:
+               return hasBreak(s.Stmt, label, implicit)
+
+       case *syntax.BranchStmt:
+               if s.Tok == syntax.Break {
+                       if s.Label == nil {
+                               return implicit
+                       }
+                       if s.Label.Value == label {
+                               return true
+                       }
+               }
+
+       case *syntax.BlockStmt:
+               return hasBreakList(s.List, label, implicit)
+
+       case *syntax.IfStmt:
+               if hasBreak(s.Then, label, implicit) ||
+                       s.Else != nil && hasBreak(s.Else, label, implicit) {
+                       return true
+               }
+
+       case *syntax.SwitchStmt:
+               if label != "" && hasBreakCaseList(s.Body, label, false) {
+                       return true
+               }
+
+       case *syntax.SelectStmt:
+               if label != "" && hasBreakCommList(s.Body, label, false) {
+                       return true
+               }
+
+       case *syntax.ForStmt:
+               if label != "" && hasBreak(s.Body, label, false) {
+                       return true
+               }
+       }
+
+       return false
+}
+
+func hasBreakList(list []syntax.Stmt, label string, implicit bool) bool {
+       for _, s := range list {
+               if hasBreak(s, label, implicit) {
+                       return true
+               }
+       }
+       return false
+}
+
+func hasBreakCaseList(list []*syntax.CaseClause, label string, implicit bool) bool {
+       for _, s := range list {
+               if hasBreakList(s.Body, label, implicit) {
+                       return true
+               }
+       }
+       return false
+}
+
+func hasBreakCommList(list []*syntax.CommClause, label string, implicit bool) bool {
+       for _, s := range list {
+               if hasBreakList(s.Body, label, implicit) {
+                       return true
+               }
+       }
+       return false
+}
diff --git a/src/cmd/compile/internal/types2/sanitize.go b/src/cmd/compile/internal/types2/sanitize.go
new file mode 100644 (file)
index 0000000..bac5694
--- /dev/null
@@ -0,0 +1,149 @@
+// UNREVIEWED
+// Copyright 2020 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
+
+func sanitizeInfo(info *Info) {
+       var s sanitizer = make(map[Type]Type)
+
+       // Note: Some map entries are not references.
+       // If modified, they must be assigned back.
+
+       for e, tv := range info.Types {
+               tv.Type = s.typ(tv.Type)
+               info.Types[e] = tv
+       }
+
+       for e, inf := range info.Inferred {
+               for i, targ := range inf.Targs {
+                       inf.Targs[i] = s.typ(targ)
+               }
+               inf.Sig = s.typ(inf.Sig).(*Signature)
+               info.Inferred[e] = inf
+       }
+
+       for _, obj := range info.Defs {
+               if obj != nil {
+                       obj.setType(s.typ(obj.Type()))
+               }
+       }
+
+       for _, obj := range info.Uses {
+               if obj != nil {
+                       obj.setType(s.typ(obj.Type()))
+               }
+       }
+
+       // TODO(gri) sanitize as needed
+       // - info.Implicits
+       // - info.Selections
+       // - info.Scopes
+       // - info.InitOrder
+}
+
+type sanitizer map[Type]Type
+
+func (s sanitizer) typ(typ Type) Type {
+       if t, found := s[typ]; found {
+               return t
+       }
+       s[typ] = typ
+
+       switch t := typ.(type) {
+       case nil, *Basic, *bottom, *top:
+               // nothing to do
+
+       case *Array:
+               t.elem = s.typ(t.elem)
+
+       case *Slice:
+               t.elem = s.typ(t.elem)
+
+       case *Struct:
+               s.varList(t.fields)
+
+       case *Pointer:
+               t.base = s.typ(t.base)
+
+       case *Tuple:
+               s.tuple(t)
+
+       case *Signature:
+               s.var_(t.recv)
+               s.tuple(t.params)
+               s.tuple(t.results)
+
+       case *Sum:
+               s.typeList(t.types)
+
+       case *Interface:
+               s.funcList(t.methods)
+               s.typ(t.types)
+               s.typeList(t.embeddeds)
+               s.funcList(t.allMethods)
+               s.typ(t.allTypes)
+
+       case *Map:
+               t.key = s.typ(t.key)
+               t.elem = s.typ(t.elem)
+
+       case *Chan:
+               t.elem = s.typ(t.elem)
+
+       case *Named:
+               t.orig = s.typ(t.orig)
+               t.underlying = s.typ(t.underlying)
+               s.typeList(t.targs)
+               s.funcList(t.methods)
+
+       case *TypeParam:
+               t.bound = s.typ(t.bound)
+
+       case *instance:
+               typ = t.expand()
+               s[t] = typ
+
+       default:
+               unimplemented()
+       }
+
+       return typ
+}
+
+func (s sanitizer) var_(v *Var) {
+       if v != nil {
+               v.typ = s.typ(v.typ)
+       }
+}
+
+func (s sanitizer) varList(list []*Var) {
+       for _, v := range list {
+               s.var_(v)
+       }
+}
+
+func (s sanitizer) tuple(t *Tuple) {
+       if t != nil {
+               s.varList(t.vars)
+       }
+}
+
+func (s sanitizer) func_(f *Func) {
+       if f != nil {
+               f.typ = s.typ(f.typ)
+       }
+}
+
+func (s sanitizer) funcList(list []*Func) {
+       for _, f := range list {
+               s.func_(f)
+       }
+}
+
+func (s sanitizer) typeList(list []Type) {
+       for i, t := range list {
+               list[i] = s.typ(t)
+       }
+}
diff --git a/src/cmd/compile/internal/types2/scope.go b/src/cmd/compile/internal/types2/scope.go
new file mode 100644 (file)
index 0000000..fd0b624
--- /dev/null
@@ -0,0 +1,216 @@
+// Copyright 2013 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.
+
+// This file implements Scopes.
+
+package types2
+
+import (
+       "bytes"
+       "cmd/compile/internal/syntax"
+       "fmt"
+       "io"
+       "sort"
+       "strings"
+)
+
+// A Scope maintains a set of objects and links to its containing
+// (parent) and contained (children) scopes. Objects may be inserted
+// and looked up by name. The zero value for Scope is a ready-to-use
+// empty scope.
+type Scope struct {
+       parent   *Scope
+       children []*Scope
+       elems    map[string]Object // lazily allocated
+       pos, end syntax.Pos        // scope extent; may be invalid
+       comment  string            // for debugging only
+       isFunc   bool              // set if this is a function scope (internal use only)
+}
+
+// NewScope returns a new, empty scope contained in the given parent
+// scope, if any. The comment is for debugging only.
+func NewScope(parent *Scope, pos, end syntax.Pos, comment string) *Scope {
+       s := &Scope{parent, nil, nil, pos, end, comment, false}
+       // don't add children to Universe scope!
+       if parent != nil && parent != Universe {
+               parent.children = append(parent.children, s)
+       }
+       return s
+}
+
+// Parent returns the scope's containing (parent) scope.
+func (s *Scope) Parent() *Scope { return s.parent }
+
+// Len returns the number of scope elements.
+func (s *Scope) Len() int { return len(s.elems) }
+
+// Names returns the scope's element names in sorted order.
+func (s *Scope) Names() []string {
+       names := make([]string, len(s.elems))
+       i := 0
+       for name := range s.elems {
+               names[i] = name
+               i++
+       }
+       sort.Strings(names)
+       return names
+}
+
+// NumChildren returns the number of scopes nested in s.
+func (s *Scope) NumChildren() int { return len(s.children) }
+
+// Child returns the i'th child scope for 0 <= i < NumChildren().
+func (s *Scope) Child(i int) *Scope { return s.children[i] }
+
+// Lookup returns the object in scope s with the given name if such an
+// object exists; otherwise the result is nil.
+func (s *Scope) Lookup(name string) Object {
+       return s.elems[name]
+}
+
+// LookupParent follows the parent chain of scopes starting with s until
+// it finds a scope where Lookup(name) returns a non-nil object, and then
+// returns that scope and object. If a valid position pos is provided,
+// only objects that were declared at or before pos are considered.
+// If no such scope and object exists, the result is (nil, nil).
+//
+// Note that obj.Parent() may be different from the returned scope if the
+// object was inserted into the scope and already had a parent at that
+// time (see Insert). This can only happen for dot-imported objects
+// whose scope is the scope of the package that exported them.
+func (s *Scope) LookupParent(name string, pos syntax.Pos) (*Scope, Object) {
+       for ; s != nil; s = s.parent {
+               if obj := s.elems[name]; obj != nil && (!pos.IsKnown() || cmpPos(obj.scopePos(), pos) <= 0) {
+                       return s, obj
+               }
+       }
+       return nil, nil
+}
+
+// Insert attempts to insert an object obj into scope s.
+// If s already contains an alternative object alt with
+// the same name, Insert leaves s unchanged and returns alt.
+// Otherwise it inserts obj, sets the object's parent scope
+// if not already set, and returns nil.
+func (s *Scope) Insert(obj Object) Object {
+       name := obj.Name()
+       if alt := s.elems[name]; alt != nil {
+               return alt
+       }
+       if s.elems == nil {
+               s.elems = make(map[string]Object)
+       }
+       s.elems[name] = obj
+       if obj.Parent() == nil {
+               obj.setParent(s)
+       }
+       return nil
+}
+
+// Squash merges s with its parent scope p by adding all
+// objects of s to p, adding all children of s to the
+// children of p, and removing s from p's children.
+// The function f is called for each object obj in s which
+// has an object alt in p. s should be discarded after
+// having been squashed.
+func (s *Scope) Squash(err func(obj, alt Object)) {
+       p := s.parent
+       assert(p != nil)
+       for _, obj := range s.elems {
+               obj.setParent(nil)
+               if alt := p.Insert(obj); alt != nil {
+                       err(obj, alt)
+               }
+       }
+
+       j := -1 // index of s in p.children
+       for i, ch := range p.children {
+               if ch == s {
+                       j = i
+                       break
+               }
+       }
+       assert(j >= 0)
+       k := len(p.children) - 1
+       p.children[j] = p.children[k]
+       p.children = p.children[:k]
+
+       p.children = append(p.children, s.children...)
+
+       s.children = nil
+       s.elems = nil
+}
+
+// Pos and End describe the scope's source code extent [pos, end).
+// The results are guaranteed to be valid only if the type-checked
+// AST has complete position information. The extent is undefined
+// for Universe and package scopes.
+func (s *Scope) Pos() syntax.Pos { return s.pos }
+func (s *Scope) End() syntax.Pos { return s.end }
+
+// Contains reports whether pos is within the scope's extent.
+// The result is guaranteed to be valid only if the type-checked
+// AST has complete position information.
+func (s *Scope) Contains(pos syntax.Pos) bool {
+       return cmpPos(s.pos, pos) <= 0 && cmpPos(pos, s.end) < 0
+}
+
+// Innermost returns the innermost (child) scope containing
+// pos. If pos is not within any scope, the result is nil.
+// The result is also nil for the Universe scope.
+// The result is guaranteed to be valid only if the type-checked
+// AST has complete position information.
+func (s *Scope) Innermost(pos syntax.Pos) *Scope {
+       // Package scopes do not have extents since they may be
+       // discontiguous, so iterate over the package's files.
+       if s.parent == Universe {
+               for _, s := range s.children {
+                       if inner := s.Innermost(pos); inner != nil {
+                               return inner
+                       }
+               }
+       }
+
+       if s.Contains(pos) {
+               for _, s := range s.children {
+                       if s.Contains(pos) {
+                               return s.Innermost(pos)
+                       }
+               }
+               return s
+       }
+       return nil
+}
+
+// WriteTo writes a string representation of the scope to w,
+// with the scope elements sorted by name.
+// The level of indentation is controlled by n >= 0, with
+// n == 0 for no indentation.
+// If recurse is set, it also writes nested (children) scopes.
+func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) {
+       const ind = ".  "
+       indn := strings.Repeat(ind, n)
+
+       fmt.Fprintf(w, "%s%s scope %p {\n", indn, s.comment, s)
+
+       indn1 := indn + ind
+       for _, name := range s.Names() {
+               fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name])
+       }
+
+       if recurse {
+               for _, s := range s.children {
+                       s.WriteTo(w, n+1, recurse)
+               }
+       }
+
+       fmt.Fprintf(w, "%s}\n", indn)
+}
+
+// String returns a string representation of the scope, for debugging.
+func (s *Scope) String() string {
+       var buf bytes.Buffer
+       s.WriteTo(&buf, 0, false)
+       return buf.String()
+}
diff --git a/src/cmd/compile/internal/types2/selection.go b/src/cmd/compile/internal/types2/selection.go
new file mode 100644 (file)
index 0000000..8128aee
--- /dev/null
@@ -0,0 +1,143 @@
+// Copyright 2013 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.
+
+// This file implements Selections.
+
+package types2
+
+import (
+       "bytes"
+       "fmt"
+)
+
+// SelectionKind describes the kind of a selector expression x.f
+// (excluding qualified identifiers).
+type SelectionKind int
+
+const (
+       FieldVal   SelectionKind = iota // x.f is a struct field selector
+       MethodVal                       // x.f is a method selector
+       MethodExpr                      // x.f is a method expression
+)
+
+// A Selection describes a selector expression x.f.
+// For the declarations:
+//
+//     type T struct{ x int; E }
+//     type E struct{}
+//     func (e E) m() {}
+//     var p *T
+//
+// the following relations exist:
+//
+//     Selector    Kind          Recv    Obj    Type       Index     Indirect
+//
+//     p.x         FieldVal      T       x      int        {0}       true
+//     p.m         MethodVal     *T      m      func()     {1, 0}    true
+//     T.m         MethodExpr    T       m      func(T)    {1, 0}    false
+//
+type Selection struct {
+       kind     SelectionKind
+       recv     Type   // type of x
+       obj      Object // object denoted by x.f
+       index    []int  // path from x to x.f
+       indirect bool   // set if there was any pointer indirection on the path
+}
+
+// Kind returns the selection kind.
+func (s *Selection) Kind() SelectionKind { return s.kind }
+
+// Recv returns the type of x in x.f.
+func (s *Selection) Recv() Type { return s.recv }
+
+// Obj returns the object denoted by x.f; a *Var for
+// a field selection, and a *Func in all other cases.
+func (s *Selection) Obj() Object { return s.obj }
+
+// Type returns the type of x.f, which may be different from the type of f.
+// See Selection for more information.
+func (s *Selection) Type() Type {
+       switch s.kind {
+       case MethodVal:
+               // The type of x.f is a method with its receiver type set
+               // to the type of x.
+               sig := *s.obj.(*Func).typ.(*Signature)
+               recv := *sig.recv
+               recv.typ = s.recv
+               sig.recv = &recv
+               return &sig
+
+       case MethodExpr:
+               // The type of x.f is a function (without receiver)
+               // and an additional first argument with the same type as x.
+               // TODO(gri) Similar code is already in call.go - factor!
+               // TODO(gri) Compute this eagerly to avoid allocations.
+               sig := *s.obj.(*Func).typ.(*Signature)
+               arg0 := *sig.recv
+               sig.recv = nil
+               arg0.typ = s.recv
+               var params []*Var
+               if sig.params != nil {
+                       params = sig.params.vars
+               }
+               sig.params = NewTuple(append([]*Var{&arg0}, params...)...)
+               return &sig
+       }
+
+       // In all other cases, the type of x.f is the type of x.
+       return s.obj.Type()
+}
+
+// Index describes the path from x to f in x.f.
+// The last index entry is the field or method index of the type declaring f;
+// either:
+//
+//     1) the list of declared methods of a named type; or
+//     2) the list of methods of an interface type; or
+//     3) the list of fields of a struct type.
+//
+// The earlier index entries are the indices of the embedded fields implicitly
+// traversed to get from (the type of) x to f, starting at embedding depth 0.
+func (s *Selection) Index() []int { return s.index }
+
+// Indirect reports whether any pointer indirection was required to get from
+// x to f in x.f.
+func (s *Selection) Indirect() bool { return s.indirect }
+
+func (s *Selection) String() string { return SelectionString(s, nil) }
+
+// SelectionString returns the string form of s.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+//
+// Examples:
+//     "field (T) f int"
+//     "method (T) f(X) Y"
+//     "method expr (T) f(X) Y"
+//
+func SelectionString(s *Selection, qf Qualifier) string {
+       var k string
+       switch s.kind {
+       case FieldVal:
+               k = "field "
+       case MethodVal:
+               k = "method "
+       case MethodExpr:
+               k = "method expr "
+       default:
+               unreachable()
+       }
+       var buf bytes.Buffer
+       buf.WriteString(k)
+       buf.WriteByte('(')
+       WriteType(&buf, s.Recv(), qf)
+       fmt.Fprintf(&buf, ") %s", s.obj.Name())
+       if T := s.Type(); s.kind == FieldVal {
+               buf.WriteByte(' ')
+               WriteType(&buf, T, qf)
+       } else {
+               WriteSignature(&buf, T.(*Signature), qf)
+       }
+       return buf.String()
+}
diff --git a/src/cmd/compile/internal/types2/self_test.go b/src/cmd/compile/internal/types2/self_test.go
new file mode 100644 (file)
index 0000000..6d7971e
--- /dev/null
@@ -0,0 +1,97 @@
+// UNREVIEWED
+// Copyright 2013 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/syntax"
+       "flag"
+       "fmt"
+       "path/filepath"
+       "testing"
+       "time"
+
+       . "cmd/compile/internal/types2"
+)
+
+var benchmark = flag.Bool("b", false, "run benchmarks")
+
+func TestSelf(t *testing.T) {
+       files, err := pkgFiles(".")
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       conf := Config{Importer: defaultImporter()}
+       _, err = conf.Check("go/types", files, nil)
+       if err != nil {
+               // Importing go/constant doesn't work in the
+               // build dashboard environment. Don't report an error
+               // for now so that the build remains green.
+               // TODO(gri) fix this
+               t.Log(err) // replace w/ t.Fatal eventually
+               return
+       }
+}
+
+func TestBenchmark(t *testing.T) {
+       if !*benchmark {
+               return
+       }
+
+       // We're not using testing's benchmarking mechanism directly
+       // because we want custom output.
+
+       for _, p := range []string{"types", "constant", filepath.Join("internal", "gcimporter")} {
+               path := filepath.Join("..", p)
+               runbench(t, path, false)
+               runbench(t, path, true)
+               fmt.Println()
+       }
+}
+
+func runbench(t *testing.T, path string, ignoreFuncBodies bool) {
+       files, err := pkgFiles(path)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       b := testing.Benchmark(func(b *testing.B) {
+               for i := 0; i < b.N; i++ {
+                       conf := Config{IgnoreFuncBodies: ignoreFuncBodies}
+                       conf.Check(path, files, nil)
+               }
+       })
+
+       // determine line count
+       var lines uint
+       for _, f := range files {
+               lines += f.EOF.Line()
+       }
+
+       d := time.Duration(b.NsPerOp())
+       fmt.Printf(
+               "%s: %s for %d lines (%d lines/s), ignoreFuncBodies = %v\n",
+               filepath.Base(path), d, lines, int64(float64(lines)/d.Seconds()), ignoreFuncBodies,
+       )
+}
+
+func pkgFiles(path string) ([]*syntax.File, error) {
+       filenames, err := pkgFilenames(path) // from stdlib_test.go
+       if err != nil {
+               return nil, err
+       }
+
+       var files []*syntax.File
+       for _, filename := range filenames {
+               file, err := syntax.ParseFile(filename, nil, nil, 0)
+               if err != nil {
+                       return nil, err
+               }
+               files = append(files, file)
+       }
+
+       return files, nil
+}
diff --git a/src/cmd/compile/internal/types2/sizes.go b/src/cmd/compile/internal/types2/sizes.go
new file mode 100644 (file)
index 0000000..cae71c1
--- /dev/null
@@ -0,0 +1,266 @@
+// UNREVIEWED
+// Copyright 2013 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.
+
+// This file implements Sizes.
+
+package types2
+
+// Sizes defines the sizing functions for package unsafe.
+type Sizes interface {
+       // Alignof returns the alignment of a variable of type T.
+       // Alignof must implement the alignment guarantees required by the spec.
+       Alignof(T Type) int64
+
+       // Offsetsof returns the offsets of the given struct fields, in bytes.
+       // Offsetsof must implement the offset guarantees required by the spec.
+       Offsetsof(fields []*Var) []int64
+
+       // Sizeof returns the size of a variable of type T.
+       // Sizeof must implement the size guarantees required by the spec.
+       Sizeof(T Type) int64
+}
+
+// StdSizes is a convenience type for creating commonly used Sizes.
+// It makes the following simplifying assumptions:
+//
+//     - The size of explicitly sized basic types (int16, etc.) is the
+//       specified size.
+//     - The size of strings and interfaces is 2*WordSize.
+//     - The size of slices is 3*WordSize.
+//     - The size of an array of n elements corresponds to the size of
+//       a struct of n consecutive fields of the array's element type.
+//      - The size of a struct is the offset of the last field plus that
+//       field's size. As with all element types, if the struct is used
+//       in an array its size must first be aligned to a multiple of the
+//       struct's alignment.
+//     - All other types have size WordSize.
+//     - Arrays and structs are aligned per spec definition; all other
+//       types are naturally aligned with a maximum alignment MaxAlign.
+//
+// *StdSizes implements Sizes.
+//
+type StdSizes struct {
+       WordSize int64 // word size in bytes - must be >= 4 (32bits)
+       MaxAlign int64 // maximum alignment in bytes - must be >= 1
+}
+
+func (s *StdSizes) Alignof(T Type) int64 {
+       // For arrays and structs, alignment is defined in terms
+       // of alignment of the elements and fields, respectively.
+       switch t := optype(T.Under()).(type) {
+       case *Array:
+               // spec: "For a variable x of array type: unsafe.Alignof(x)
+               // is the same as unsafe.Alignof(x[0]), but at least 1."
+               return s.Alignof(t.elem)
+       case *Struct:
+               // spec: "For a variable x of struct type: unsafe.Alignof(x)
+               // is the largest of the values unsafe.Alignof(x.f) for each
+               // field f of x, but at least 1."
+               max := int64(1)
+               for _, f := range t.fields {
+                       if a := s.Alignof(f.typ); a > max {
+                               max = a
+                       }
+               }
+               return max
+       case *Slice, *Interface:
+               // Multiword data structures are effectively structs
+               // in which each element has size WordSize.
+               return s.WordSize
+       case *Basic:
+               // Strings are like slices and interfaces.
+               if t.Info()&IsString != 0 {
+                       return s.WordSize
+               }
+       }
+       a := s.Sizeof(T) // may be 0
+       // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
+       if a < 1 {
+               return 1
+       }
+       // complex{64,128} are aligned like [2]float{32,64}.
+       if isComplex(T) {
+               a /= 2
+       }
+       if a > s.MaxAlign {
+               return s.MaxAlign
+       }
+       return a
+}
+
+func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
+       offsets := make([]int64, len(fields))
+       var o int64
+       for i, f := range fields {
+               a := s.Alignof(f.typ)
+               o = align(o, a)
+               offsets[i] = o
+               o += s.Sizeof(f.typ)
+       }
+       return offsets
+}
+
+var basicSizes = [...]byte{
+       Bool:       1,
+       Int8:       1,
+       Int16:      2,
+       Int32:      4,
+       Int64:      8,
+       Uint8:      1,
+       Uint16:     2,
+       Uint32:     4,
+       Uint64:     8,
+       Float32:    4,
+       Float64:    8,
+       Complex64:  8,
+       Complex128: 16,
+}
+
+func (s *StdSizes) Sizeof(T Type) int64 {
+       switch t := optype(T.Under()).(type) {
+       case *Basic:
+               assert(isTyped(T))
+               k := t.kind
+               if int(k) < len(basicSizes) {
+                       if s := basicSizes[k]; s > 0 {
+                               return int64(s)
+                       }
+               }
+               if k == String {
+                       return s.WordSize * 2
+               }
+       case *Array:
+               n := t.len
+               if n <= 0 {
+                       return 0
+               }
+               // n > 0
+               a := s.Alignof(t.elem)
+               z := s.Sizeof(t.elem)
+               return align(z, a)*(n-1) + z
+       case *Slice:
+               return s.WordSize * 3
+       case *Struct:
+               n := t.NumFields()
+               if n == 0 {
+                       return 0
+               }
+               offsets := s.Offsetsof(t.fields)
+               return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
+       case *Sum:
+               panic("Sizeof unimplemented for type sum")
+       case *Interface:
+               return s.WordSize * 2
+       }
+       return s.WordSize // catch-all
+}
+
+// common architecture word sizes and alignments
+var gcArchSizes = map[string]*StdSizes{
+       "386":      {4, 4},
+       "arm":      {4, 4},
+       "arm64":    {8, 8},
+       "amd64":    {8, 8},
+       "amd64p32": {4, 8},
+       "mips":     {4, 4},
+       "mipsle":   {4, 4},
+       "mips64":   {8, 8},
+       "mips64le": {8, 8},
+       "ppc64":    {8, 8},
+       "ppc64le":  {8, 8},
+       "riscv64":  {8, 8},
+       "s390x":    {8, 8},
+       "sparc64":  {8, 8},
+       "wasm":     {8, 8},
+       // When adding more architectures here,
+       // update the doc string of SizesFor below.
+}
+
+// SizesFor returns the Sizes used by a compiler for an architecture.
+// The result is nil if a compiler/architecture pair is not known.
+//
+// Supported architectures for compiler "gc":
+// "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle",
+// "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "sparc64", "wasm".
+func SizesFor(compiler, arch string) Sizes {
+       var m map[string]*StdSizes
+       switch compiler {
+       case "gc":
+               m = gcArchSizes
+       case "gccgo":
+               m = gccgoArchSizes
+       default:
+               return nil
+       }
+       s, ok := m[arch]
+       if !ok {
+               return nil
+       }
+       return s
+}
+
+// stdSizes is used if Config.Sizes == nil.
+var stdSizes = SizesFor("gc", "amd64")
+
+func (conf *Config) alignof(T Type) int64 {
+       if s := conf.Sizes; s != nil {
+               if a := s.Alignof(T); a >= 1 {
+                       return a
+               }
+               panic("Config.Sizes.Alignof returned an alignment < 1")
+       }
+       return stdSizes.Alignof(T)
+}
+
+func (conf *Config) offsetsof(T *Struct) []int64 {
+       var offsets []int64
+       if T.NumFields() > 0 {
+               // compute offsets on demand
+               if s := conf.Sizes; s != nil {
+                       offsets = s.Offsetsof(T.fields)
+                       // sanity checks
+                       if len(offsets) != T.NumFields() {
+                               panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
+                       }
+                       for _, o := range offsets {
+                               if o < 0 {
+                                       panic("Config.Sizes.Offsetsof returned an offset < 0")
+                               }
+                       }
+               } else {
+                       offsets = stdSizes.Offsetsof(T.fields)
+               }
+       }
+       return offsets
+}
+
+// offsetof returns the offset of the field specified via
+// the index sequence relative to typ. All embedded fields
+// must be structs (rather than pointer to structs).
+func (conf *Config) offsetof(typ Type, index []int) int64 {
+       var o int64
+       for _, i := range index {
+               s := typ.Struct()
+               o += conf.offsetsof(s)[i]
+               typ = s.fields[i].typ
+       }
+       return o
+}
+
+func (conf *Config) sizeof(T Type) int64 {
+       if s := conf.Sizes; s != nil {
+               if z := s.Sizeof(T); z >= 0 {
+                       return z
+               }
+               panic("Config.Sizes.Sizeof returned a size < 0")
+       }
+       return stdSizes.Sizeof(T)
+}
+
+// align returns the smallest y >= x such that y % a == 0.
+func align(x, a int64) int64 {
+       y := x + a - 1
+       return y - y%a
+}
diff --git a/src/cmd/compile/internal/types2/sizes_test.go b/src/cmd/compile/internal/types2/sizes_test.go
new file mode 100644 (file)
index 0000000..b246909
--- /dev/null
@@ -0,0 +1,108 @@
+// UNREVIEWED
+// Copyright 2016 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.
+
+// This file contains tests for sizes.
+
+package types2_test
+
+import (
+       "cmd/compile/internal/syntax"
+       "cmd/compile/internal/types2"
+       "testing"
+)
+
+// findStructType typechecks src and returns the first struct type encountered.
+func findStructType(t *testing.T, src string) *types2.Struct {
+       f, err := parseSrc("x.go", src)
+       if err != nil {
+               t.Fatal(err)
+       }
+       info := types2.Info{Types: make(map[syntax.Expr]types2.TypeAndValue)}
+       var conf types2.Config
+       _, err = conf.Check("x", []*syntax.File{f}, &info)
+       if err != nil {
+               t.Fatal(err)
+       }
+       for _, tv := range info.Types {
+               if ts, ok := tv.Type.(*types2.Struct); ok {
+                       return ts
+               }
+       }
+       t.Fatalf("failed to find a struct type in src:\n%s\n", src)
+       return nil
+}
+
+// Issue 16316
+func TestMultipleSizeUse(t *testing.T) {
+       const src = `
+package main
+
+type S struct {
+    i int
+    b bool
+    s string
+    n int
+}
+`
+       ts := findStructType(t, src)
+       sizes := types2.StdSizes{WordSize: 4, MaxAlign: 4}
+       if got := sizes.Sizeof(ts); got != 20 {
+               t.Errorf("Sizeof(%v) with WordSize 4 = %d want 20", ts, got)
+       }
+       sizes = types2.StdSizes{WordSize: 8, MaxAlign: 8}
+       if got := sizes.Sizeof(ts); got != 40 {
+               t.Errorf("Sizeof(%v) with WordSize 8 = %d want 40", ts, got)
+       }
+}
+
+// Issue 16464
+func TestAlignofNaclSlice(t *testing.T) {
+       const src = `
+package main
+
+var s struct {
+       x *int
+       y []byte
+}
+`
+       ts := findStructType(t, src)
+       sizes := &types2.StdSizes{WordSize: 4, MaxAlign: 8}
+       var fields []*types2.Var
+       // Make a copy manually :(
+       for i := 0; i < ts.NumFields(); i++ {
+               fields = append(fields, ts.Field(i))
+       }
+       offsets := sizes.Offsetsof(fields)
+       if offsets[0] != 0 || offsets[1] != 4 {
+               t.Errorf("OffsetsOf(%v) = %v want %v", ts, offsets, []int{0, 4})
+       }
+}
+
+func TestIssue16902(t *testing.T) {
+       const src = `
+package a
+
+import "unsafe"
+
+const _ = unsafe.Offsetof(struct{ x int64 }{}.x)
+`
+       f, err := parseSrc("x.go", src)
+       if err != nil {
+               t.Fatal(err)
+       }
+       info := types2.Info{Types: make(map[syntax.Expr]types2.TypeAndValue)}
+       conf := types2.Config{
+               Importer: defaultImporter(),
+               Sizes:    &types2.StdSizes{WordSize: 8, MaxAlign: 8},
+       }
+       _, err = conf.Check("x", []*syntax.File{f}, &info)
+       if err != nil {
+               t.Fatal(err)
+       }
+       for _, tv := range info.Types {
+               _ = conf.Sizes.Sizeof(tv.Type)
+               _ = conf.Sizes.Alignof(tv.Type)
+       }
+}
diff --git a/src/cmd/compile/internal/types2/stdlib_test.go b/src/cmd/compile/internal/types2/stdlib_test.go
new file mode 100644 (file)
index 0000000..ae573a4
--- /dev/null
@@ -0,0 +1,323 @@
+// UNREVIEWED
+// Copyright 2013 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.
+
+// This file tests types.Check by using it to
+// typecheck the standard library and tests.
+
+package types2_test
+
+import (
+       "bytes"
+       "cmd/compile/internal/syntax"
+       "fmt"
+       "go/build"
+       "internal/testenv"
+       "io/ioutil"
+       "os"
+       "path/filepath"
+       "runtime"
+       "strings"
+       "testing"
+       "time"
+
+       . "cmd/compile/internal/types2"
+)
+
+var stdLibImporter = defaultImporter()
+
+func TestStdlib(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       pkgCount := 0
+       duration := walkPkgDirs(filepath.Join(runtime.GOROOT(), "src"), func(dir string, filenames []string) {
+               typecheck(t, dir, filenames)
+               pkgCount++
+       }, t.Error)
+
+       if testing.Verbose() {
+               fmt.Println(pkgCount, "packages typechecked in", duration)
+       }
+}
+
+// firstComment returns the contents of the first non-empty comment in
+// the given file, "skip", or the empty string. No matter the present
+// comments, if any of them contains a build tag, the result is always
+// "skip". Only comments within the first 4K of the file are considered.
+// TODO(gri) should only read until we see "package" token.
+func firstComment(filename string) (first string) {
+       f, err := os.Open(filename)
+       if err != nil {
+               return ""
+       }
+       defer f.Close()
+
+       // read at most 4KB
+       var buf [4 << 10]byte
+       n, _ := f.Read(buf[:])
+       src := bytes.NewBuffer(buf[:n])
+
+       // TODO(gri) we need a better way to terminate CommentsDo
+       defer func() {
+               if p := recover(); p != nil {
+                       if s, ok := p.(string); ok {
+                               first = s
+                       }
+               }
+       }()
+
+       syntax.CommentsDo(src, func(_, _ uint, text string) {
+               if text[0] != '/' {
+                       return // not a comment
+               }
+
+               // extract comment text
+               if text[1] == '*' {
+                       text = text[:len(text)-2]
+               }
+               text = strings.TrimSpace(text[2:])
+
+               if strings.HasPrefix(text, "+build ") {
+                       panic("skip")
+               }
+               if first == "" {
+                       first = text // text may be "" but that's ok
+               }
+               // continue as we may still see build tags
+       })
+
+       return
+}
+
+func testTestDir(t *testing.T, path string, ignore ...string) {
+       files, err := ioutil.ReadDir(path)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       excluded := make(map[string]bool)
+       for _, filename := range ignore {
+               excluded[filename] = true
+       }
+
+       for _, f := range files {
+               // filter directory contents
+               if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") || excluded[f.Name()] {
+                       continue
+               }
+
+               // get per-file instructions
+               expectErrors := false
+               filename := filepath.Join(path, f.Name())
+               if comment := firstComment(filename); comment != "" {
+                       fields := strings.Fields(comment)
+                       switch fields[0] {
+                       case "skip", "compiledir":
+                               continue // ignore this file
+                       case "errorcheck":
+                               expectErrors = true
+                               for _, arg := range fields[1:] {
+                                       if arg == "-0" || arg == "-+" || arg == "-std" {
+                                               // Marked explicitly as not expected errors (-0),
+                                               // or marked as compiling runtime/stdlib, which is only done
+                                               // to trigger runtime/stdlib-only error output.
+                                               // In both cases, the code should typecheck.
+                                               expectErrors = false
+                                               break
+                                       }
+                               }
+                       }
+               }
+
+               // parse and type-check file
+               if testing.Verbose() {
+                       fmt.Println("\t", filename)
+               }
+               file, err := syntax.ParseFile(filename, nil, nil, 0)
+               if err == nil {
+                       conf := Config{Importer: stdLibImporter}
+                       _, err = conf.Check(filename, []*syntax.File{file}, nil)
+               }
+
+               if expectErrors {
+                       if err == nil {
+                               t.Errorf("expected errors but found none in %s", filename)
+                       }
+               } else {
+                       if err != nil {
+                               t.Error(err)
+                       }
+               }
+       }
+}
+
+func TestStdTest(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       if testing.Short() && testenv.Builder() == "" {
+               t.Skip("skipping in short mode")
+       }
+
+       testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
+               "cmplxdivide.go", // also needs file cmplxdivide1.go - ignore
+               "directive.go",   // tests compiler rejection of bad directive placement - ignore
+               "linkname2.go",   // types2 doesn't check validity of //go:xxx directives
+       )
+}
+
+func TestStdFixed(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       if testing.Short() && testenv.Builder() == "" {
+               t.Skip("skipping in short mode")
+       }
+
+       testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
+               "bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
+               "issue6889.go",   // gc-specific test
+               "issue7746.go",   // large constants - consumes too much memory
+               "issue11362.go",  // canonical import path check
+               "issue16369.go",  // go/types handles this correctly - not an issue
+               "issue18459.go",  // go/types doesn't check validity of //go:xxx directives
+               "issue18882.go",  // go/types doesn't check validity of //go:xxx directives
+               "issue20232.go",  // go/types handles larger constants than gc
+               "issue20529.go",  // go/types does not have constraints on stack size
+               "issue22200.go",  // go/types does not have constraints on stack size
+               "issue22200b.go", // go/types does not have constraints on stack size
+               "issue25507.go",  // go/types does not have constraints on stack size
+               "issue20780.go",  // go/types does not have constraints on stack size
+               "issue31747.go",  // go/types does not have constraints on language level (-lang=go1.12) (see #31793)
+               "issue34329.go",  // go/types does not have constraints on language level (-lang=go1.13) (see #31793)
+               "issue42058a.go", // go/types does not have constraints on channel element size
+               "issue42058b.go", // go/types does not have constraints on channel element size
+               "bug251.go",      // issue #34333 which was exposed with fix for #34151
+       )
+}
+
+func TestStdKen(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken"))
+}
+
+// Package paths of excluded packages.
+var excluded = map[string]bool{
+       "builtin": true,
+}
+
+// typecheck typechecks the given package files.
+func typecheck(t *testing.T, path string, filenames []string) {
+       // parse package files
+       var files []*syntax.File
+       for _, filename := range filenames {
+               errh := func(err error) { t.Error(err) }
+               file, err := syntax.ParseFile(filename, errh, nil, 0)
+               if err != nil {
+                       return
+               }
+
+               if testing.Verbose() {
+                       if len(files) == 0 {
+                               fmt.Println("package", file.PkgName.Value)
+                       }
+                       fmt.Println("\t", filename)
+               }
+
+               files = append(files, file)
+       }
+
+       // typecheck package files
+       conf := Config{
+               Error:    func(err error) { t.Error(err) },
+               Importer: stdLibImporter,
+       }
+       info := Info{Uses: make(map[*syntax.Name]Object)}
+       conf.Check(path, files, &info)
+
+       // Perform checks of API invariants.
+
+       // All Objects have a package, except predeclared ones.
+       errorError := Universe.Lookup("error").Type().Interface().ExplicitMethod(0) // (error).Error
+       for id, obj := range info.Uses {
+               predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError
+               if predeclared == (obj.Pkg() != nil) {
+                       posn := id.Pos()
+                       if predeclared {
+                               t.Errorf("%s: predeclared object with package: %s", posn, obj)
+                       } else {
+                               t.Errorf("%s: user-defined object without package: %s", posn, obj)
+                       }
+               }
+       }
+}
+
+// pkgFilenames returns the list of package filenames for the given directory.
+func pkgFilenames(dir string) ([]string, error) {
+       ctxt := build.Default
+       ctxt.CgoEnabled = false
+       pkg, err := ctxt.ImportDir(dir, 0)
+       if err != nil {
+               if _, nogo := err.(*build.NoGoError); nogo {
+                       return nil, nil // no *.go files, not an error
+               }
+               return nil, err
+       }
+       if excluded[pkg.ImportPath] {
+               return nil, nil
+       }
+       var filenames []string
+       for _, name := range pkg.GoFiles {
+               filenames = append(filenames, filepath.Join(pkg.Dir, name))
+       }
+       for _, name := range pkg.TestGoFiles {
+               filenames = append(filenames, filepath.Join(pkg.Dir, name))
+       }
+       return filenames, nil
+}
+
+func walkPkgDirs(dir string, pkgh func(dir string, filenames []string), errh func(args ...interface{})) time.Duration {
+       w := walker{time.Now(), 10 * time.Millisecond, pkgh, errh}
+       w.walk(dir)
+       return time.Since(w.start)
+}
+
+type walker struct {
+       start time.Time
+       dmax  time.Duration
+       pkgh  func(dir string, filenames []string)
+       errh  func(args ...interface{})
+}
+
+func (w *walker) walk(dir string) {
+       // limit run time for short tests
+       if testing.Short() && time.Since(w.start) >= w.dmax {
+               return
+       }
+
+       fis, err := ioutil.ReadDir(dir)
+       if err != nil {
+               w.errh(err)
+               return
+       }
+
+       // apply pkgh to the files in directory dir
+       // but ignore files directly under $GOROOT/src (might be temporary test files).
+       if dir != filepath.Join(runtime.GOROOT(), "src") {
+               files, err := pkgFilenames(dir)
+               if err != nil {
+                       w.errh(err)
+                       return
+               }
+               if files != nil {
+                       w.pkgh(dir, files)
+               }
+       }
+
+       // traverse subdirectories, but don't walk into testdata
+       for _, fi := range fis {
+               if fi.IsDir() && fi.Name() != "testdata" {
+                       w.walk(filepath.Join(dir, fi.Name()))
+               }
+       }
+}
diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go
new file mode 100644 (file)
index 0000000..3463cfd
--- /dev/null
@@ -0,0 +1,916 @@
+// UNREVIEWED
+// Copyright 2012 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.
+
+// This file implements typechecking of statements.
+
+package types2
+
+import (
+       "cmd/compile/internal/syntax"
+       "go/constant"
+       "sort"
+)
+
+func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *syntax.BlockStmt, iota constant.Value) {
+       if check.conf.Trace {
+               check.trace(body.Pos(), "--- %s: %s", name, sig)
+               defer func() {
+                       check.trace(endPos(body), "--- <end>")
+               }()
+       }
+
+       // set function scope extent
+       sig.scope.pos = body.Pos()
+       sig.scope.end = endPos(body)
+
+       // save/restore current context and setup function context
+       // (and use 0 indentation at function start)
+       defer func(ctxt context, indent int) {
+               check.context = ctxt
+               check.indent = indent
+       }(check.context, check.indent)
+       check.context = context{
+               decl:  decl,
+               scope: sig.scope,
+               iota:  iota,
+               sig:   sig,
+       }
+       check.indent = 0
+
+       check.stmtList(0, body.List)
+
+       if check.hasLabel {
+               assert(!check.conf.IgnoreBranches)
+               check.labels(body)
+       }
+
+       if sig.results.Len() > 0 && !check.isTerminating(body, "") {
+               check.error(body.Rbrace, "missing return")
+       }
+
+       // TODO(gri) Should we make it an error to declare generic functions
+       //           where the type parameters are not used?
+       // 12/19/2018: Probably not - it can make sense to have an API with
+       //           all functions uniformly sharing the same type parameters.
+
+       // spec: "Implementation restriction: A compiler may make it illegal to
+       // declare a variable inside a function body if the variable is never used."
+       check.usage(sig.scope)
+}
+
+func (check *Checker) usage(scope *Scope) {
+       var unused []*Var
+       for _, elem := range scope.elems {
+               if v, _ := elem.(*Var); v != nil && !v.used {
+                       unused = append(unused, v)
+               }
+       }
+       sort.Slice(unused, func(i, j int) bool {
+               return cmpPos(unused[i].pos, unused[j].pos) < 0
+       })
+       for _, v := range unused {
+               check.softErrorf(v.pos, "%s declared but not used", v.name)
+       }
+
+       for _, scope := range scope.children {
+               // Don't go inside function literal scopes a second time;
+               // they are handled explicitly by funcBody.
+               if !scope.isFunc {
+                       check.usage(scope)
+               }
+       }
+}
+
+// stmtContext is a bitset describing which
+// control-flow statements are permissible,
+// and provides additional context information
+// for better error messages.
+type stmtContext uint
+
+const (
+       // permissible control-flow statements
+       breakOk stmtContext = 1 << iota
+       continueOk
+       fallthroughOk
+
+       // additional context information
+       finalSwitchCase
+)
+
+func (check *Checker) simpleStmt(s syntax.Stmt) {
+       if s != nil {
+               check.stmt(0, s)
+       }
+}
+
+func trimTrailingEmptyStmts(list []syntax.Stmt) []syntax.Stmt {
+       for i := len(list); i > 0; i-- {
+               if _, ok := list[i-1].(*syntax.EmptyStmt); !ok {
+                       return list[:i]
+               }
+       }
+       return nil
+}
+
+func (check *Checker) stmtList(ctxt stmtContext, list []syntax.Stmt) {
+       ok := ctxt&fallthroughOk != 0
+       inner := ctxt &^ fallthroughOk
+       list = trimTrailingEmptyStmts(list) // trailing empty statements are "invisible" to fallthrough analysis
+       for i, s := range list {
+               inner := inner
+               if ok && i+1 == len(list) {
+                       inner |= fallthroughOk
+               }
+               check.stmt(inner, s)
+       }
+}
+
+func (check *Checker) multipleSwitchDefaults(list []*syntax.CaseClause) {
+       var first *syntax.CaseClause
+       for _, c := range list {
+               if c.Cases == nil {
+                       if first != nil {
+                               check.errorf(c, "multiple defaults (first at %s)", first.Pos())
+                               // TODO(gri) probably ok to bail out after first error (and simplify this code)
+                       } else {
+                               first = c
+                       }
+               }
+       }
+}
+
+func (check *Checker) multipleSelectDefaults(list []*syntax.CommClause) {
+       var first *syntax.CommClause
+       for _, c := range list {
+               if c.Comm == nil {
+                       if first != nil {
+                               check.errorf(c, "multiple defaults (first at %s)", first.Pos())
+                               // TODO(gri) probably ok to bail out after first error (and simplify this code)
+                       } else {
+                               first = c
+                       }
+               }
+       }
+}
+
+func (check *Checker) openScope(node syntax.Node, comment string) {
+       scope := NewScope(check.scope, node.Pos(), endPos(node), comment)
+       check.recordScope(node, scope)
+       check.scope = scope
+}
+
+func (check *Checker) closeScope() {
+       check.scope = check.scope.Parent()
+}
+
+func (check *Checker) suspendedCall(keyword string, call *syntax.CallExpr) {
+       var x operand
+       var msg string
+       switch check.rawExpr(&x, call, nil) {
+       case conversion:
+               msg = "requires function call, not conversion"
+       case expression:
+               msg = "discards result of"
+       case statement:
+               return
+       default:
+               unreachable()
+       }
+       check.errorf(&x, "%s %s %s", keyword, msg, &x)
+}
+
+// goVal returns the Go value for val, or nil.
+func goVal(val constant.Value) interface{} {
+       // val should exist, but be conservative and check
+       if val == nil {
+               return nil
+       }
+       // Match implementation restriction of other compilers.
+       // gc only checks duplicates for integer, floating-point
+       // and string values, so only create Go values for these
+       // types.
+       switch val.Kind() {
+       case constant.Int:
+               if x, ok := constant.Int64Val(val); ok {
+                       return x
+               }
+               if x, ok := constant.Uint64Val(val); ok {
+                       return x
+               }
+       case constant.Float:
+               if x, ok := constant.Float64Val(val); ok {
+                       return x
+               }
+       case constant.String:
+               return constant.StringVal(val)
+       }
+       return nil
+}
+
+// A valueMap maps a case value (of a basic Go type) to a list of positions
+// where the same case value appeared, together with the corresponding case
+// types.
+// Since two case values may have the same "underlying" value but different
+// types we need to also check the value's types (e.g., byte(1) vs myByte(1))
+// when the switch expression is of interface type.
+type (
+       valueMap  map[interface{}][]valueType // underlying Go value -> valueType
+       valueType struct {
+               pos syntax.Pos
+               typ Type
+       }
+)
+
+func (check *Checker) caseValues(x *operand, values []syntax.Expr, seen valueMap) {
+L:
+       for _, e := range values {
+               var v operand
+               check.expr(&v, e)
+               if x.mode == invalid || v.mode == invalid {
+                       continue L
+               }
+               check.convertUntyped(&v, x.typ)
+               if v.mode == invalid {
+                       continue L
+               }
+               // Order matters: By comparing v against x, error positions are at the case values.
+               res := v // keep original v unchanged
+               check.comparison(&res, x, syntax.Eql)
+               if res.mode == invalid {
+                       continue L
+               }
+               if v.mode != constant_ {
+                       continue L // we're done
+               }
+               // look for duplicate values
+               if val := goVal(v.val); val != nil {
+                       // look for duplicate types for a given value
+                       // (quadratic algorithm, but these lists tend to be very short)
+                       for _, vt := range seen[val] {
+                               if check.identical(v.typ, vt.typ) {
+                                       check.errorf(&v, "duplicate case %s in expression switch", &v)
+                                       check.error(vt.pos, "\tprevious case") // secondary error, \t indented
+                                       continue L
+                               }
+                       }
+                       seen[val] = append(seen[val], valueType{v.Pos(), v.typ})
+               }
+       }
+}
+
+func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []syntax.Expr, seen map[Type]syntax.Pos, strict bool) (T Type) {
+L:
+       for _, e := range types {
+               T = check.typOrNil(e)
+               if T == Typ[Invalid] {
+                       continue L
+               }
+               if T != nil {
+                       check.ordinaryType(e.Pos(), T)
+               }
+               // look for duplicate types
+               // (quadratic algorithm, but type switches tend to be reasonably small)
+               for t, pos := range seen {
+                       if T == nil && t == nil || T != nil && t != nil && check.identical(T, t) {
+                               // talk about "case" rather than "type" because of nil case
+                               Ts := "nil"
+                               if T != nil {
+                                       Ts = T.String()
+                               }
+                               check.errorf(e, "duplicate case %s in type switch", Ts)
+                               check.error(pos, "\tprevious case") // secondary error, \t indented
+                               continue L
+                       }
+               }
+               seen[T] = e.Pos()
+               if T != nil {
+                       check.typeAssertion(e.Pos(), x, xtyp, T, strict)
+               }
+       }
+       return
+}
+
+// stmt typechecks statement s.
+func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
+       // statements must end with the same top scope as they started with
+       if debug {
+               defer func(scope *Scope) {
+                       // don't check if code is panicking
+                       if p := recover(); p != nil {
+                               panic(p)
+                       }
+                       assert(scope == check.scope)
+               }(check.scope)
+       }
+
+       // process collected function literals before scope changes
+       defer check.processDelayed(len(check.delayed))
+
+       inner := ctxt &^ (fallthroughOk | finalSwitchCase)
+       switch s := s.(type) {
+       case *syntax.EmptyStmt:
+               // ignore
+
+       case *syntax.DeclStmt:
+               check.declStmt(s.DeclList)
+
+       case *syntax.LabeledStmt:
+               check.hasLabel = !check.conf.IgnoreBranches
+               check.stmt(ctxt, s.Stmt)
+
+       case *syntax.ExprStmt:
+               // spec: "With the exception of specific built-in functions,
+               // function and method calls and receive operations can appear
+               // in statement context. Such statements may be parenthesized."
+               var x operand
+               kind := check.rawExpr(&x, s.X, nil)
+               var msg string
+               switch x.mode {
+               default:
+                       if kind == statement {
+                               return
+                       }
+                       msg = "is not used"
+               case builtin:
+                       msg = "must be called"
+               case typexpr:
+                       msg = "is not an expression"
+               }
+               check.errorf(&x, "%s %s", &x, msg)
+
+       case *syntax.SendStmt:
+               var ch, x operand
+               check.expr(&ch, s.Chan)
+               check.expr(&x, s.Value)
+               if ch.mode == invalid || x.mode == invalid {
+                       return
+               }
+
+               tch := ch.typ.Chan()
+               if tch == nil {
+                       check.invalidOpf(s, "cannot send to non-chan type %s", ch.typ)
+                       return
+               }
+
+               if tch.dir == RecvOnly {
+                       check.invalidOpf(s, "cannot send to receive-only type %s", tch)
+                       return
+               }
+
+               check.assignment(&x, tch.elem, "send")
+
+       case *syntax.AssignStmt:
+               lhs := unpackExpr(s.Lhs)
+               rhs := unpackExpr(s.Rhs)
+               if s.Op == 0 || s.Op == syntax.Def {
+                       // regular assignment or short variable declaration
+                       if len(lhs) == 0 {
+                               check.invalidASTf(s, "missing lhs in assignment")
+                               return
+                       }
+                       if s.Op == syntax.Def {
+                               check.shortVarDecl(s.Pos(), lhs, rhs)
+                       } else {
+                               // regular assignment
+                               check.assignVars(lhs, rhs)
+                       }
+               } else {
+                       // assignment operations
+                       if len(lhs) != 1 || len(rhs) != 1 {
+                               check.errorf(s, "assignment operation %s requires single-valued expressions", s.Op)
+                               return
+                       }
+
+                       // provide better error messages for x++ and x--
+                       if rhs[0] == syntax.ImplicitOne {
+                               var x operand
+                               check.expr(&x, lhs[0])
+                               if x.mode == invalid {
+                                       return
+                               }
+                               if !isNumeric(x.typ) {
+                                       check.invalidOpf(lhs[0], "%s%s%s (non-numeric type %s)", lhs[0], s.Op, s.Op, x.typ)
+                                       return
+                               }
+                       }
+
+                       var x operand
+                       check.binary(&x, nil, lhs[0], rhs[0], s.Op, rhs[0].Pos()) // TODO(gri) should have TokPos here (like in go/types)
+                       if x.mode == invalid {
+                               return
+                       }
+                       check.assignVar(lhs[0], &x)
+               }
+
+       // case *syntax.GoStmt:
+       //      check.suspendedCall("go", s.Call)
+
+       // case *syntax.DeferStmt:
+       //      check.suspendedCall("defer", s.Call)
+       case *syntax.CallStmt:
+               // TODO(gri) get rid of this conversion to string
+               kind := "go"
+               if s.Tok == syntax.Defer {
+                       kind = "defer"
+               }
+               check.suspendedCall(kind, s.Call)
+
+       case *syntax.ReturnStmt:
+               res := check.sig.results
+               results := unpackExpr(s.Results)
+               if res.Len() > 0 {
+                       // function returns results
+                       // (if one, say the first, result parameter is named, all of them are named)
+                       if len(results) == 0 && res.vars[0].name != "" {
+                               // spec: "Implementation restriction: A compiler may disallow an empty expression
+                               // list in a "return" statement if a different entity (constant, type, or variable)
+                               // with the same name as a result parameter is in scope at the place of the return."
+                               for _, obj := range res.vars {
+                                       if alt := check.lookup(obj.name); alt != nil && alt != obj {
+                                               check.errorf(s, "result parameter %s not in scope at return", obj.name)
+                                               check.errorf(alt, "\tinner declaration of %s", obj)
+                                               // ok to continue
+                                       }
+                               }
+                       } else {
+                               // return has results or result parameters are unnamed
+                               check.initVars(res.vars, results, s.Pos())
+                       }
+               } else if len(results) > 0 {
+                       check.error(results[0], "no result values expected")
+                       check.use(results...)
+               }
+
+       case *syntax.BranchStmt:
+               if check.conf.IgnoreBranches {
+                       break
+               }
+
+               if s.Label != nil {
+                       check.hasLabel = true
+                       return // checked in 2nd pass (check.labels)
+               }
+               switch s.Tok {
+               case syntax.Break:
+                       if ctxt&breakOk == 0 {
+                               check.error(s, "break not in for, switch, or select statement")
+                       }
+               case syntax.Continue:
+                       if ctxt&continueOk == 0 {
+                               check.error(s, "continue not in for statement")
+                       }
+               case syntax.Fallthrough:
+                       if ctxt&fallthroughOk == 0 {
+                               msg := "fallthrough statement out of place"
+                               if ctxt&finalSwitchCase != 0 {
+                                       msg = "cannot fallthrough final case in switch"
+                               }
+                               check.error(s, msg)
+                       }
+               case syntax.Goto:
+                       // goto's must have labels, should have been caught above
+                       fallthrough
+               default:
+                       check.invalidASTf(s, "branch statement: %s", s.Tok)
+               }
+
+       case *syntax.BlockStmt:
+               check.openScope(s, "block")
+               defer check.closeScope()
+
+               check.stmtList(inner, s.List)
+
+       case *syntax.IfStmt:
+               check.openScope(s, "if")
+               defer check.closeScope()
+
+               check.simpleStmt(s.Init)
+               var x operand
+               check.expr(&x, s.Cond)
+               if x.mode != invalid && !isBoolean(x.typ) {
+                       check.error(s.Cond, "non-boolean condition in if statement")
+               }
+               check.stmt(inner, s.Then)
+               // The parser produces a correct AST but if it was modified
+               // elsewhere the else branch may be invalid. Check again.
+               switch s.Else.(type) {
+               case nil:
+                       // valid or error already reported
+               case *syntax.IfStmt, *syntax.BlockStmt:
+                       check.stmt(inner, s.Else)
+               default:
+                       check.error(s.Else, "invalid else branch in if statement")
+               }
+
+       case *syntax.SwitchStmt:
+               inner |= breakOk
+               check.openScope(s, "switch")
+               defer check.closeScope()
+
+               check.simpleStmt(s.Init)
+
+               if g, _ := s.Tag.(*syntax.TypeSwitchGuard); g != nil {
+                       check.typeSwitchStmt(inner, s, g)
+               } else {
+                       check.switchStmt(inner, s)
+               }
+
+       case *syntax.SelectStmt:
+               inner |= breakOk
+
+               check.multipleSelectDefaults(s.Body)
+
+               for _, clause := range s.Body {
+                       if clause == nil {
+                               continue // error reported before
+                       }
+
+                       // clause.Comm must be a SendStmt, RecvStmt, or default case
+                       valid := false
+                       var rhs syntax.Expr // rhs of RecvStmt, or nil
+                       switch s := clause.Comm.(type) {
+                       case nil, *syntax.SendStmt:
+                               valid = true
+                       case *syntax.AssignStmt:
+                               if _, ok := s.Rhs.(*syntax.ListExpr); !ok {
+                                       rhs = s.Rhs
+                               }
+                       case *syntax.ExprStmt:
+                               rhs = s.X
+                       }
+
+                       // if present, rhs must be a receive operation
+                       if rhs != nil {
+                               if x, _ := unparen(rhs).(*syntax.Operation); x != nil && x.Y == nil && x.Op == syntax.Recv {
+                                       valid = true
+                               }
+                       }
+
+                       if !valid {
+                               check.error(clause.Comm, "select case must be send or receive (possibly with assignment)")
+                               continue
+                       }
+
+                       check.openScope(s, "case")
+                       if clause.Comm != nil {
+                               check.stmt(inner, clause.Comm)
+                       }
+                       check.stmtList(inner, clause.Body)
+                       check.closeScope()
+               }
+
+       case *syntax.ForStmt:
+               inner |= breakOk | continueOk
+               check.openScope(s, "for")
+               defer check.closeScope()
+
+               if rclause, _ := s.Init.(*syntax.RangeClause); rclause != nil {
+                       check.rangeStmt(inner, s, rclause)
+                       break
+               }
+
+               check.simpleStmt(s.Init)
+               if s.Cond != nil {
+                       var x operand
+                       check.expr(&x, s.Cond)
+                       if x.mode != invalid && !isBoolean(x.typ) {
+                               check.error(s.Cond, "non-boolean condition in for statement")
+                       }
+               }
+               check.simpleStmt(s.Post)
+               // spec: "The init statement may be a short variable
+               // declaration, but the post statement must not."
+               if s, _ := s.Post.(*syntax.AssignStmt); s != nil && s.Op == syntax.Def {
+                       // The parser already reported an error.
+                       // Don't call useLHS here because we want to use the lhs in
+                       // this erroneous statement so that we don't get errors about
+                       // these lhs variables being declared but not used.
+                       check.use(s.Lhs) // avoid follow-up errors
+               }
+               check.stmt(inner, s.Body)
+
+       default:
+               check.error(s, "invalid statement")
+       }
+}
+
+func (check *Checker) switchStmt(inner stmtContext, s *syntax.SwitchStmt) {
+       // init statement already handled
+
+       var x operand
+       if s.Tag != nil {
+               check.expr(&x, s.Tag)
+               // By checking assignment of x to an invisible temporary
+               // (as a compiler would), we get all the relevant checks.
+               check.assignment(&x, nil, "switch expression")
+               if x.mode != invalid && !Comparable(x.typ) && !hasNil(x.typ) {
+                       check.errorf(&x, "cannot switch on %s (%s is not comparable)", &x, x.typ)
+                       x.mode = invalid
+               }
+       } else {
+               // spec: "A missing switch expression is
+               // equivalent to the boolean value true."
+               x.mode = constant_
+               x.typ = Typ[Bool]
+               x.val = constant.MakeBool(true)
+               // TODO(gri) should have a better position here
+               pos := s.Rbrace
+               if len(s.Body) > 0 {
+                       pos = s.Body[0].Pos()
+               }
+               x.expr = syntax.NewName(pos, "true")
+       }
+
+       check.multipleSwitchDefaults(s.Body)
+
+       seen := make(valueMap) // map of seen case values to positions and types
+       for i, clause := range s.Body {
+               if clause == nil {
+                       check.invalidASTf(clause, "incorrect expression switch case")
+                       continue
+               }
+               check.caseValues(&x, unpackExpr(clause.Cases), seen)
+               check.openScope(clause, "case")
+               inner := inner
+               if i+1 < len(s.Body) {
+                       inner |= fallthroughOk
+               } else {
+                       inner |= finalSwitchCase
+               }
+               check.stmtList(inner, clause.Body)
+               check.closeScope()
+       }
+}
+
+func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, guard *syntax.TypeSwitchGuard) {
+       // init statement already handled
+
+       // A type switch guard must be of the form:
+       //
+       //     TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
+       //                          \__lhs__/        \___rhs___/
+
+       // check lhs, if any
+       lhs := guard.Lhs
+       if lhs != nil {
+               if lhs.Value == "_" {
+                       // _ := x.(type) is an invalid short variable declaration
+                       check.softErrorf(lhs, "no new variable on left side of :=")
+                       lhs = nil // avoid declared but not used error below
+               } else {
+                       check.recordDef(lhs, nil) // lhs variable is implicitly declared in each cause clause
+               }
+       }
+
+       // check rhs
+       var x operand
+       check.expr(&x, guard.X)
+       if x.mode == invalid {
+               return
+       }
+       xtyp, _ := x.typ.Under().(*Interface)
+       if xtyp == nil {
+               check.errorf(&x, "%s is not an interface type", &x)
+               return
+       }
+       check.ordinaryType(x.Pos(), xtyp)
+
+       check.multipleSwitchDefaults(s.Body)
+
+       var lhsVars []*Var                // list of implicitly declared lhs variables
+       seen := make(map[Type]syntax.Pos) // map of seen types to positions
+       for _, clause := range s.Body {
+               if clause == nil {
+                       check.invalidASTf(s, "incorrect type switch case")
+                       continue
+               }
+               // Check each type in this type switch case.
+               cases := unpackExpr(clause.Cases)
+               T := check.caseTypes(&x, xtyp, cases, seen, false)
+               check.openScope(clause, "case")
+               // If lhs exists, declare a corresponding variable in the case-local scope.
+               if lhs != nil {
+                       // spec: "The TypeSwitchGuard may include a short variable declaration.
+                       // When that form is used, the variable is declared at the beginning of
+                       // the implicit block in each clause. In clauses with a case listing
+                       // exactly one type, the variable has that type; otherwise, the variable
+                       // has the type of the expression in the TypeSwitchGuard."
+                       if len(cases) != 1 || T == nil {
+                               T = x.typ
+                       }
+                       obj := NewVar(lhs.Pos(), check.pkg, lhs.Value, T)
+                       scopePos := clause.Pos() // for default clause (len(List) == 0)
+                       if n := len(cases); n > 0 {
+                               scopePos = endPos(cases[n-1])
+                       }
+                       check.declare(check.scope, nil, obj, scopePos)
+                       check.recordImplicit(clause, obj)
+                       // For the "declared but not used" error, all lhs variables act as
+                       // one; i.e., if any one of them is 'used', all of them are 'used'.
+                       // Collect them for later analysis.
+                       lhsVars = append(lhsVars, obj)
+               }
+               check.stmtList(inner, clause.Body)
+               check.closeScope()
+       }
+
+       // If lhs exists, we must have at least one lhs variable that was used.
+       if lhs != nil {
+               var used bool
+               for _, v := range lhsVars {
+                       if v.used {
+                               used = true
+                       }
+                       v.used = true // avoid usage error when checking entire function
+               }
+               if !used {
+                       check.softErrorf(lhs, "%s declared but not used", lhs.Value)
+               }
+       }
+}
+
+func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *syntax.RangeClause) {
+       // scope already opened
+
+       // check expression to iterate over
+       var x operand
+       check.expr(&x, rclause.X)
+
+       // determine lhs, if any
+       sKey := rclause.Lhs // possibly nil
+       var sValue syntax.Expr
+       if p, _ := sKey.(*syntax.ListExpr); p != nil {
+               if len(p.ElemList) != 2 {
+                       check.invalidASTf(s, "invalid lhs in range clause")
+                       return
+               }
+               sKey = p.ElemList[0]
+               sValue = p.ElemList[1]
+       }
+
+       // determine key/value types
+       var key, val Type
+       if x.mode != invalid {
+               typ := optype(x.typ.Under())
+               if _, ok := typ.(*Chan); ok && sValue != nil {
+                       // TODO(gri) this also needs to happen for channels in generic variables
+                       check.softErrorf(sValue, "range over %s permits only one iteration variable", &x)
+                       // ok to continue
+               }
+               var msg string
+               key, val, msg = rangeKeyVal(typ, isVarName(sKey), isVarName(sValue))
+               if key == nil || msg != "" {
+                       if msg != "" {
+                               msg = ": " + msg
+                       }
+                       check.softErrorf(&x, "cannot range over %s%s", &x, msg)
+                       // ok to continue
+               }
+       }
+
+       // check assignment to/declaration of iteration variables
+       // (irregular assignment, cannot easily map to existing assignment checks)
+
+       // lhs expressions and initialization value (rhs) types
+       lhs := [2]syntax.Expr{sKey, sValue}
+       rhs := [2]Type{key, val} // key, val may be nil
+
+       if rclause.Def {
+               // short variable declaration; variable scope starts after the range clause
+               // (the for loop opens a new scope, so variables on the lhs never redeclare
+               // previously declared variables)
+               var vars []*Var
+               for i, lhs := range lhs {
+                       if lhs == nil {
+                               continue
+                       }
+
+                       // determine lhs variable
+                       var obj *Var
+                       if ident, _ := lhs.(*syntax.Name); ident != nil {
+                               // declare new variable
+                               name := ident.Value
+                               obj = NewVar(ident.Pos(), check.pkg, name, nil)
+                               check.recordDef(ident, obj)
+                               // _ variables don't count as new variables
+                               if name != "_" {
+                                       vars = append(vars, obj)
+                               }
+                       } else {
+                               check.errorf(lhs, "cannot declare %s", lhs)
+                               obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
+                       }
+
+                       // initialize lhs variable
+                       if typ := rhs[i]; typ != nil {
+                               x.mode = value
+                               x.expr = lhs // we don't have a better rhs expression to use here
+                               x.typ = typ
+                               check.initVar(obj, &x, "range clause")
+                       } else {
+                               obj.typ = Typ[Invalid]
+                               obj.used = true // don't complain about unused variable
+                       }
+               }
+
+               // declare variables
+               if len(vars) > 0 {
+                       scopePos := endPos(rclause.X) // TODO(gri) should this just be s.Body.Pos (spec clarification)?
+                       for _, obj := range vars {
+                               // spec: "The scope of a constant or variable identifier declared inside
+                               // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
+                               // for short variable declarations) and ends at the end of the innermost
+                               // containing block."
+                               check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
+                       }
+               } else {
+                       check.error(s, "no new variables on left side of :=")
+               }
+       } else {
+               // ordinary assignment
+               for i, lhs := range lhs {
+                       if lhs == nil {
+                               continue
+                       }
+                       if typ := rhs[i]; typ != nil {
+                               x.mode = value
+                               x.expr = lhs // we don't have a better rhs expression to use here
+                               x.typ = typ
+                               check.assignVar(lhs, &x)
+                       }
+               }
+       }
+
+       check.stmt(inner, s.Body)
+}
+
+// isVarName reports whether x is a non-nil, non-blank (_) expression.
+func isVarName(x syntax.Expr) bool {
+       if x == nil {
+               return false
+       }
+       ident, _ := unparen(x).(*syntax.Name)
+       return ident == nil || ident.Value != "_"
+}
+
+// rangeKeyVal returns the key and value type produced by a range clause
+// over an expression of type typ, and possibly an error message. If the
+// range clause is not permitted the returned key is nil or msg is not
+// empty (in that case we still may have a non-nil key type which can be
+// used to reduce the chance for follow-on errors).
+// The wantKey, wantVal, and hasVal flags indicate which of the iteration
+// variables are used or present; this matters if we range over a generic
+// type where not all keys or values are of the same type.
+func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
+       switch typ := typ.(type) {
+       case *Basic:
+               if isString(typ) {
+                       return Typ[Int], universeRune, "" // use 'rune' name
+               }
+       case *Array:
+               return Typ[Int], typ.elem, ""
+       case *Slice:
+               return Typ[Int], typ.elem, ""
+       case *Pointer:
+               if typ := typ.base.Array(); typ != nil {
+                       return Typ[Int], typ.elem, ""
+               }
+       case *Map:
+               return typ.key, typ.elem, ""
+       case *Chan:
+               var msg string
+               if typ.dir == SendOnly {
+                       msg = "receive from send-only channel"
+               }
+               return typ.elem, Typ[Invalid], msg
+       case *Sum:
+               first := true
+               var key, val Type
+               var msg string
+               typ.is(func(t Type) bool {
+                       k, v, m := rangeKeyVal(t.Under(), wantKey, wantVal)
+                       if k == nil || m != "" {
+                               key, val, msg = k, v, m
+                               return false
+                       }
+                       if first {
+                               key, val, msg = k, v, m
+                               first = false
+                               return true
+                       }
+                       if wantKey && !Identical(key, k) {
+                               key, val, msg = nil, nil, "all possible values must have the same key type"
+                               return false
+                       }
+                       if wantVal && !Identical(val, v) {
+                               key, val, msg = nil, nil, "all possible values must have the same element type"
+                               return false
+                       }
+                       return true
+               })
+               return key, val, msg
+       }
+       return nil, nil, ""
+}
diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go
new file mode 100644 (file)
index 0000000..27405d8
--- /dev/null
@@ -0,0 +1,539 @@
+// Copyright 2018 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.
+
+// This file implements instantiation of generic types
+// through substitution of type parameters by actual
+// types.
+
+package types2
+
+import (
+       "bytes"
+       "cmd/compile/internal/syntax"
+       "fmt"
+)
+
+type substMap struct {
+       // The targs field is currently needed for *Named type substitution.
+       // TODO(gri) rewrite that code, get rid of this field, and make this
+       //           struct just the map (proj)
+       targs []Type
+       proj  map[*TypeParam]Type
+}
+
+// makeSubstMap creates a new substitution map mapping tpars[i] to targs[i].
+// If targs[i] is nil, tpars[i] is not substituted.
+func makeSubstMap(tpars []*TypeName, targs []Type) *substMap {
+       assert(len(tpars) == len(targs))
+       proj := make(map[*TypeParam]Type, len(tpars))
+       for i, tpar := range tpars {
+               // We must expand type arguments otherwise *instance
+               // types end up as components in composite types.
+               // TODO(gri) explain why this causes problems, if it does
+               targ := expand(targs[i]) // possibly nil
+               targs[i] = targ
+               proj[tpar.typ.(*TypeParam)] = targ
+       }
+       return &substMap{targs, proj}
+}
+
+func (m *substMap) String() string {
+       return fmt.Sprintf("%s", m.proj)
+}
+
+func (m *substMap) empty() bool {
+       return len(m.proj) == 0
+}
+
+func (m *substMap) lookup(tpar *TypeParam) Type {
+       if t := m.proj[tpar]; t != nil {
+               return t
+       }
+       return tpar
+}
+
+func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslist []syntax.Pos) (res Type) {
+       if check.conf.Trace {
+               check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs))
+               check.indent++
+               defer func() {
+                       check.indent--
+                       var under Type
+                       if res != nil {
+                               // Calling Under() here may lead to endless instantiations.
+                               // Test case: type T[P any] T[P]
+                               // TODO(gri) investigate if that's a bug or to be expected.
+                               under = res.Underlying()
+                       }
+                       check.trace(pos, "=> %s (under = %s)", res, under)
+               }()
+       }
+
+       assert(len(poslist) <= len(targs))
+
+       // TODO(gri) What is better here: work with TypeParams, or work with TypeNames?
+       var tparams []*TypeName
+       switch t := typ.(type) {
+       case *Named:
+               tparams = t.tparams
+       case *Signature:
+               tparams = t.tparams
+               defer func() {
+                       // If we had an unexpected failure somewhere don't panic below when
+                       // asserting res.(*Signature). Check for *Signature in case Typ[Invalid]
+                       // is returned.
+                       if _, ok := res.(*Signature); !ok {
+                               return
+                       }
+                       // 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).
+                       if t == res {
+                               copy := *t
+                               res = &copy
+                       }
+                       // After instantiating a generic signature, it is not generic
+                       // anymore; we need to set tparams to nil.
+                       res.(*Signature).tparams = nil
+               }()
+
+       default:
+               check.dump("%v: cannot instantiate %v", pos, typ)
+               unreachable() // only defined types and (defined) functions can be generic
+
+       }
+
+       // the number of supplied types must match the number of type parameters
+       if len(targs) != len(tparams) {
+               // TODO(gri) provide better error message
+               check.errorf(pos, "got %d arguments but %d type parameters", len(targs), len(tparams))
+               return Typ[Invalid]
+       }
+
+       if len(tparams) == 0 {
+               return typ // nothing to do (minor optimization)
+       }
+
+       smap := makeSubstMap(tparams, targs)
+
+       // check bounds
+       for i, tname := range tparams {
+               tpar := tname.typ.(*TypeParam)
+               iface := tpar.Bound()
+               if iface.Empty() {
+                       continue // no type bound
+               }
+
+               targ := targs[i]
+
+               // best position for error reporting
+               pos := pos
+               if i < len(poslist) {
+                       pos = poslist[i]
+               }
+
+               // The type parameter bound is parameterized with the same type parameters
+               // as the instantiated type; before we can use it for bounds checking we
+               // need to instantiate it with the type arguments with which we instantiate
+               // the parameterized type.
+               iface = check.subst(pos, iface, smap).(*Interface)
+
+               // targ must implement iface (methods)
+               // - check only if we have methods
+               check.completeInterface(nopos, iface)
+               if len(iface.allMethods) > 0 {
+                       // If the type argument is a pointer to a type parameter, the type argument's
+                       // method set is empty.
+                       // TODO(gri) is this what we want? (spec question)
+                       if base, isPtr := deref(targ); isPtr && base.TypeParam() != nil {
+                               check.errorf(pos, "%s has no methods", targ)
+                               break
+                       }
+                       if m, wrong := check.missingMethod(targ, iface, true); m != nil {
+                               // TODO(gri) needs to print updated name to avoid major confusion in error message!
+                               //           (print warning for now)
+                               // Old warning:
+                               // check.softErrorf(pos, "%s does not satisfy %s (warning: name not updated) = %s (missing method %s)", targ, tpar.bound, iface, m)
+                               if m.name == "==" {
+                                       // We don't want to report "missing method ==".
+                                       check.softErrorf(pos, "%s does not satisfy comparable", targ)
+                               } else if wrong != nil {
+                                       // TODO(gri) This can still report uninstantiated types which makes the error message
+                                       //           more difficult to read then necessary.
+                                       check.softErrorf(pos,
+                                               "%s does not satisfy %s: wrong method signature\n\tgot  %s\n\twant %s",
+                                               targ, tpar.bound, wrong, m,
+                                       )
+                               } else {
+                                       check.softErrorf(pos, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name)
+                               }
+                               break
+                       }
+               }
+
+               // targ's underlying type must also be one of the interface types listed, if any
+               if iface.allTypes == nil {
+                       continue // nothing to do
+               }
+
+               // If targ is itself a type parameter, each of its possible types, but at least one, must be in the
+               // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types).
+               if targ := targ.TypeParam(); targ != nil {
+                       targBound := targ.Bound()
+                       if targBound.allTypes == nil {
+                               check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ)
+                               break
+                       }
+                       for _, t := range unpack(targBound.allTypes) {
+                               if !iface.isSatisfiedBy(t.Under()) {
+                                       // TODO(gri) match this error message with the one below (or vice versa)
+                                       check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes)
+                                       break
+                               }
+                       }
+                       break
+               }
+
+               // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any.
+               if !iface.isSatisfiedBy(targ) {
+                       check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ.Under(), iface.allTypes)
+                       break
+               }
+       }
+
+       return check.subst(pos, typ, smap)
+}
+
+// subst returns the type typ with its type parameters tpars replaced by
+// the corresponding type arguments targs, recursively.
+// subst is functional in the sense that it doesn't modify the incoming
+// type. If a substitution took place, the result type is different from
+// from the incoming type.
+func (check *Checker) subst(pos syntax.Pos, typ Type, smap *substMap) Type {
+       if smap.empty() {
+               return typ
+       }
+
+       // common cases
+       switch t := typ.(type) {
+       case *Basic:
+               return typ // nothing to do
+       case *TypeParam:
+               return smap.lookup(t)
+       }
+
+       // general case
+       subst := subster{check, pos, make(map[Type]Type), smap}
+       return subst.typ(typ)
+}
+
+type subster struct {
+       check *Checker
+       pos   syntax.Pos
+       cache map[Type]Type
+       smap  *substMap
+}
+
+func (subst *subster) typ(typ Type) Type {
+       switch t := typ.(type) {
+       case nil:
+               // Call typOrNil if it's possible that typ is nil.
+               panic("nil typ")
+
+       case *Basic, *bottom, *top:
+               // nothing to do
+
+       case *Array:
+               elem := subst.typOrNil(t.elem)
+               if elem != t.elem {
+                       return &Array{len: t.len, elem: elem}
+               }
+
+       case *Slice:
+               elem := subst.typOrNil(t.elem)
+               if elem != t.elem {
+                       return &Slice{elem: elem}
+               }
+
+       case *Struct:
+               if fields, copied := subst.varList(t.fields); copied {
+                       return &Struct{fields: fields, tags: t.tags}
+               }
+
+       case *Pointer:
+               base := subst.typ(t.base)
+               if base != t.base {
+                       return &Pointer{base: base}
+               }
+
+       case *Tuple:
+               return subst.tuple(t)
+
+       case *Signature:
+               // TODO(gri) rethink the recv situation with respect to methods on parameterized types
+               // recv := subst.var_(t.recv) // TODO(gri) this causes a stack overflow - explain
+               recv := t.recv
+               params := subst.tuple(t.params)
+               results := subst.tuple(t.results)
+               if recv != t.recv || params != t.params || results != t.results {
+                       return &Signature{
+                               rparams: t.rparams,
+                               // TODO(gri) Why can't we nil out tparams here, rather than in
+                               //           instantiate above?
+                               tparams:  t.tparams,
+                               scope:    t.scope,
+                               recv:     recv,
+                               params:   params,
+                               results:  results,
+                               variadic: t.variadic,
+                       }
+               }
+
+       case *Sum:
+               types, copied := subst.typeList(t.types)
+               if copied {
+                       // Don't do it manually, with a Sum literal: the new
+                       // types list may not be unique and NewSum may remove
+                       // duplicates.
+                       return NewSum(types)
+               }
+
+       case *Interface:
+               methods, mcopied := subst.funcList(t.methods)
+               types := t.types
+               if t.types != nil {
+                       types = subst.typ(t.types)
+               }
+               embeddeds, ecopied := subst.typeList(t.embeddeds)
+               if mcopied || types != t.types || ecopied {
+                       iface := &Interface{methods: methods, types: types, embeddeds: embeddeds}
+                       subst.check.posMap[iface] = subst.check.posMap[t] // satisfy completeInterface requirement
+                       subst.check.completeInterface(nopos, iface)
+                       return iface
+               }
+
+       case *Map:
+               key := subst.typ(t.key)
+               elem := subst.typ(t.elem)
+               if key != t.key || elem != t.elem {
+                       return &Map{key: key, elem: elem}
+               }
+
+       case *Chan:
+               elem := subst.typ(t.elem)
+               if elem != t.elem {
+                       return &Chan{dir: t.dir, elem: elem}
+               }
+
+       case *Named:
+               subst.check.indent++
+               defer func() {
+                       subst.check.indent--
+               }()
+               dump := func(format string, args ...interface{}) {
+                       if subst.check.conf.Trace {
+                               subst.check.trace(subst.pos, format, args...)
+                       }
+               }
+
+               if t.tparams == nil {
+                       dump(">>> %s is not parameterized", t)
+                       return t // type is not parameterized
+               }
+
+               var new_targs []Type
+
+               if len(t.targs) > 0 {
+                       // already instantiated
+                       dump(">>> %s already instantiated", t)
+                       assert(len(t.targs) == len(t.tparams))
+                       // For each (existing) type argument targ, determine if it needs
+                       // to be substituted; i.e., if it is or contains a type parameter
+                       // that has a type argument for it.
+                       for i, targ := range t.targs {
+                               dump(">>> %d targ = %s", i, targ)
+                               new_targ := subst.typ(targ)
+                               if new_targ != targ {
+                                       dump(">>> substituted %d targ %s => %s", i, targ, new_targ)
+                                       if new_targs == nil {
+                                               new_targs = make([]Type, len(t.tparams))
+                                               copy(new_targs, t.targs)
+                                       }
+                                       new_targs[i] = new_targ
+                               }
+                       }
+
+                       if new_targs == nil {
+                               dump(">>> nothing to substitute in %s", t)
+                               return t // nothing to substitute
+                       }
+               } else {
+                       // not yet instantiated
+                       dump(">>> first instantiation of %s", t)
+                       new_targs = subst.smap.targs
+               }
+
+               // before creating a new named type, check if we have this one already
+               h := instantiatedHash(t, new_targs)
+               dump(">>> new type hash: %s", h)
+               if named, found := subst.check.typMap[h]; found {
+                       dump(">>> found %s", named)
+                       subst.cache[t] = named
+                       return named
+               }
+
+               // create a new named type and populate caches to avoid endless recursion
+               tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil)
+               named := subst.check.NewNamed(tname, t.underlying, t.methods) // method signatures are updated lazily
+               named.tparams = t.tparams                                     // new type is still parameterized
+               named.targs = new_targs
+               subst.check.typMap[h] = named
+               subst.cache[t] = named
+
+               // do the substitution
+               dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, new_targs)
+               named.underlying = subst.typOrNil(t.underlying)
+               named.orig = named.underlying // for cycle detection (Checker.validType)
+
+               return named
+
+       case *TypeParam:
+               return subst.smap.lookup(t)
+
+       case *instance:
+               // TODO(gri) can we avoid the expansion here and just substitute the type parameters?
+               return subst.typ(t.expand())
+
+       default:
+               unimplemented()
+       }
+
+       return typ
+}
+
+// TODO(gri) Eventually, this should be more sophisticated.
+//           It won't work correctly for locally declared types.
+func instantiatedHash(typ *Named, targs []Type) string {
+       var buf bytes.Buffer
+       writeTypeName(&buf, typ.obj, nil)
+       buf.WriteByte('[')
+       writeTypeList(&buf, targs, nil, nil)
+       buf.WriteByte(']')
+
+       // With respect to the represented type, whether a
+       // type is fully expanded or stored as instance
+       // does not matter - they are the same types.
+       // Remove the instanceMarkers printed for instances.
+       res := buf.Bytes()
+       i := 0
+       for _, b := range res {
+               if b != instanceMarker {
+                       res[i] = b
+                       i++
+               }
+       }
+
+       return string(res[:i])
+}
+
+func typeListString(list []Type) string {
+       var buf bytes.Buffer
+       writeTypeList(&buf, list, nil, nil)
+       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.
+func (subst *subster) typOrNil(typ Type) Type {
+       if typ == nil {
+               return Typ[Invalid]
+       }
+       return subst.typ(typ)
+}
+
+func (subst *subster) var_(v *Var) *Var {
+       if v != nil {
+               if typ := subst.typ(v.typ); typ != v.typ {
+                       copy := *v
+                       copy.typ = typ
+                       return &copy
+               }
+       }
+       return v
+}
+
+func (subst *subster) tuple(t *Tuple) *Tuple {
+       if t != nil {
+               if vars, copied := subst.varList(t.vars); copied {
+                       return &Tuple{vars: vars}
+               }
+       }
+       return t
+}
+
+func (subst *subster) varList(in []*Var) (out []*Var, copied bool) {
+       out = in
+       for i, v := range in {
+               if w := subst.var_(v); w != v {
+                       if !copied {
+                               // first variable that got substituted => allocate new out slice
+                               // and copy all variables
+                               new := make([]*Var, len(in))
+                               copy(new, out)
+                               out = new
+                               copied = true
+                       }
+                       out[i] = w
+               }
+       }
+       return
+}
+
+func (subst *subster) func_(f *Func) *Func {
+       if f != nil {
+               if typ := subst.typ(f.typ); typ != f.typ {
+                       copy := *f
+                       copy.typ = typ
+                       return &copy
+               }
+       }
+       return f
+}
+
+func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) {
+       out = in
+       for i, f := range in {
+               if g := subst.func_(f); g != f {
+                       if !copied {
+                               // first function that got substituted => allocate new out slice
+                               // and copy all functions
+                               new := make([]*Func, len(in))
+                               copy(new, out)
+                               out = new
+                               copied = true
+                       }
+                       out[i] = g
+               }
+       }
+       return
+}
+
+func (subst *subster) typeList(in []Type) (out []Type, copied bool) {
+       out = in
+       for i, t := range in {
+               if u := subst.typ(t); u != t {
+                       if !copied {
+                               // first function that got substituted => allocate new out slice
+                               // and copy all functions
+                               new := make([]Type, len(in))
+                               copy(new, out)
+                               out = new
+                               copied = true
+                       }
+                       out[i] = u
+               }
+       }
+       return
+}
diff --git a/src/cmd/compile/internal/types2/testdata/blank.src b/src/cmd/compile/internal/types2/testdata/blank.src
new file mode 100644 (file)
index 0000000..6a2507f
--- /dev/null
@@ -0,0 +1,5 @@
+// Copyright 2014 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 _ /* ERROR invalid package name */
diff --git a/src/cmd/compile/internal/types2/testdata/builtins.go2 b/src/cmd/compile/internal/types2/testdata/builtins.go2
new file mode 100644 (file)
index 0000000..3918d83
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2020 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.
+
+// This file tests built-in calls on generic types.
+
+package builtins
+
+type Bmc interface {
+       type map[rune]string, chan int
+}
+
+type Bms interface {
+       type map[string]int, []int
+}
+
+type Bcs interface {
+       type chan bool, []float64
+}
+
+type Bss interface {
+       type []int, []string
+}
+
+func _[T any] () {
+       _ = make(T /* ERROR invalid argument */ )
+       _ = make(T /* ERROR invalid argument */ , 10)
+       _ = make(T /* ERROR invalid argument */ , 10, 20)
+}
+
+func _[T Bmc] () {
+       _ = make(T)
+       _ = make(T, 10)
+       _ = make /* ERROR expects 1 or 2 arguments */ (T, 10, 20)
+}
+
+func _[T Bms] () {
+       _ = make /* ERROR expects 2 arguments */ (T)
+       _ = make(T, 10)
+       _ = make /* ERROR expects 2 arguments */ (T, 10, 20)
+}
+
+func _[T Bcs] () {
+       _ = make /* ERROR expects 2 arguments */ (T)
+       _ = make(T, 10)
+       _ = make /* ERROR expects 2 arguments */ (T, 10, 20)
+}
+
+func _[T Bss] () {
+       _ = make /* ERROR expects 2 or 3 arguments */ (T)
+       _ = make(T, 10)
+       _ = make(T, 10, 20)
+}
diff --git a/src/cmd/compile/internal/types2/testdata/builtins.src b/src/cmd/compile/internal/types2/testdata/builtins.src
new file mode 100644 (file)
index 0000000..69cc487
--- /dev/null
@@ -0,0 +1,902 @@
+// Copyright 2012 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.
+
+// builtin calls
+
+package builtins
+
+import "unsafe"
+
+func f0() {}
+
+func append1() {
+       var b byte
+       var x int
+       var s []byte
+       _ = append() // ERROR not enough arguments
+       _ = append("foo" /* ERROR not a slice */ )
+       _ = append(nil /* ERROR not a slice */ , s)
+       _ = append(x /* ERROR not a slice */ , s)
+       _ = append(s)
+       _ = append(s, nil...)
+       append /* ERROR not used */ (s)
+
+       _ = append(s, b)
+       _ = append(s, x /* ERROR cannot use x */ )
+       _ = append(s, s /* ERROR cannot use s */ )
+       _ = append(s... ) /* ERROR not enough arguments */
+       _ = append(s, b, s /* ERROR too many arguments */ ... )
+       _ = append(s, 1, 2, 3)
+       _ = append(s, 1, 2, 3, x /* ERROR cannot use x */ , 5, 6, 6)
+       _ = append(s, 1, 2 /* ERROR too many arguments */ , s... )
+       _ = append([]interface{}(nil), 1, 2, "foo", x, 3.1425, false)
+
+       type S []byte
+       type T string
+       var t T
+       _ = append(s, "foo" /* ERROR cannot convert */ )
+       _ = append(s, "foo"...)
+       _ = append(S(s), "foo" /* ERROR cannot convert */ )
+       _ = append(S(s), "foo"...)
+       _ = append(s, t /* ERROR cannot use t */ )
+       _ = append(s, t...)
+       _ = append(s, T("foo")...)
+       _ = append(S(s), t /* ERROR cannot use t */ )
+       _ = append(S(s), t...)
+       _ = append(S(s), T("foo")...)
+       _ = append([]string{}, t /* ERROR cannot use t */ , "foo")
+       _ = append([]T{}, t, "foo")
+}
+
+// from the spec
+func append2() {
+       s0 := []int{0, 0}
+       s1 := append(s0, 2)                // append a single element     s1 == []int{0, 0, 2}
+       s2 := append(s1, 3, 5, 7)          // append multiple elements    s2 == []int{0, 0, 2, 3, 5, 7}
+       s3 := append(s2, s0...)            // append a slice              s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}
+       s4 := append(s3[3:6], s3[2:]...)   // append overlapping slice    s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
+
+       var t []interface{}
+       t = append(t, 42, 3.1415, "foo")   //                             t == []interface{}{42, 3.1415, "foo"}
+
+       var b []byte
+       b = append(b, "bar"...)            // append string contents      b == []byte{'b', 'a', 'r' }
+
+       _ = s4
+}
+
+func append3() {
+       f1 := func() (s []int) { return }
+       f2 := func() (s []int, x int) { return }
+       f3 := func() (s []int, x, y int) { return }
+       f5 := func() (s []interface{}, x int, y float32, z string, b bool) { return }
+       ff := func() (int, float32) { return 0, 0 }
+       _ = append(f0 /* ERROR used as value */ ())
+       _ = append(f1())
+       _ = append(f2())
+       _ = append(f3())
+       _ = append(f5())
+       _ = append(ff /* ERROR not a slice */ ()) // TODO(gri) better error message
+}
+
+func cap1() {
+       var a [10]bool
+       var p *[20]int
+       var c chan string
+       _ = cap() // ERROR not enough arguments
+       _ = cap(1, 2) // ERROR too many arguments
+       _ = cap(42 /* ERROR invalid */)
+       const _3 = cap(a)
+       assert(_3 == 10)
+       const _4 = cap(p)
+       assert(_4 == 20)
+       _ = cap(c)
+       cap /* ERROR not used */ (c)
+
+       // issue 4744
+       type T struct{ a [10]int }
+       const _ = cap(((*T)(nil)).a)
+
+       var s [][]byte
+       _ = cap(s)
+       _ = cap(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func cap2() {
+       f1a := func() (a [10]int) { return }
+       f1s := func() (s []int) { return }
+       f2 := func() (s []int, x int) { return }
+       _ = cap(f0 /* ERROR used as value */ ())
+       _ = cap(f1a())
+       _ = cap(f1s())
+       _ = cap(f2()) // ERROR too many arguments
+}
+
+// test cases for issue 7387
+func cap3() {
+       var f = func() int { return 0 }
+       var x = f()
+       const (
+               _ = cap([4]int{})
+               _ = cap([4]int{x})
+               _ = cap /* ERROR not constant */ ([4]int{f()})
+               _ = cap /* ERROR not constant */ ([4]int{cap([]int{})})
+               _ = cap([4]int{cap([4]int{})})
+       )
+       var y float64
+       var z complex128
+       const (
+               _ = cap([4]float64{})
+               _ = cap([4]float64{y})
+               _ = cap([4]float64{real(2i)})
+               _ = cap /* ERROR not constant */ ([4]float64{real(z)})
+       )
+       var ch chan [10]int
+       const (
+               _ = cap /* ERROR not constant */ (<-ch)
+               _ = cap /* ERROR not constant */ ([4]int{(<-ch)[0]})
+       )
+}
+
+func close1() {
+       var c chan int
+       var r <-chan int
+       close() // ERROR not enough arguments
+       close(1, 2) // ERROR too many arguments
+       close(42 /* ERROR not a channel */)
+       close(r /* ERROR receive-only channel */)
+       close(c)
+       _ = close /* ERROR used as value */ (c)
+
+       var s []chan int
+       close(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func close2() {
+       f1 := func() (ch chan int) { return }
+       f2 := func() (ch chan int, x int) { return }
+       close(f0 /* ERROR used as value */ ())
+       close(f1())
+       close(f2()) // ERROR too many arguments
+}
+
+func complex1() {
+       var i32 int32
+       var f32 float32
+       var f64 float64
+       var c64 complex64
+       var c128 complex128
+       _ = complex() // ERROR not enough arguments
+       _ = complex(1) // ERROR not enough arguments
+       _ = complex(true /* ERROR mismatched types */ , 0)
+       _ = complex(i32 /* ERROR expected floating-point */ , 0)
+       _ = complex("foo" /* ERROR mismatched types */ , 0)
+       _ = complex(c64 /* ERROR expected floating-point */ , 0)
+       _ = complex(0 /* ERROR mismatched types */ , true)
+       _ = complex(0 /* ERROR expected floating-point */ , i32)
+       _ = complex(0 /* ERROR mismatched types */ , "foo")
+       _ = complex(0 /* ERROR expected floating-point */ , c64)
+       _ = complex(f32, f32)
+       _ = complex(f32, 1)
+       _ = complex(f32, 1.0)
+       _ = complex(f32, 'a')
+       _ = complex(f64, f64)
+       _ = complex(f64, 1)
+       _ = complex(f64, 1.0)
+       _ = complex(f64, 'a')
+       _ = complex(f32 /* ERROR mismatched types */ , f64)
+       _ = complex(f64 /* ERROR mismatched types */ , f32)
+       _ = complex(1, 1)
+       _ = complex(1, 1.1)
+       _ = complex(1, 'a')
+       complex /* ERROR not used */ (1, 2)
+
+       var _ complex64 = complex(f32, f32)
+       var _ complex64 = complex /* ERROR cannot use .* in variable declaration */ (f64, f64)
+
+       var _ complex128 = complex /* ERROR cannot use .* in variable declaration */ (f32, f32)
+       var _ complex128 = complex(f64, f64)
+
+       // untyped constants
+       const _ int = complex(1, 0)
+       const _ float32 = complex(1, 0)
+       const _ complex64 = complex(1, 0)
+       const _ complex128 = complex(1, 0)
+       const _ = complex(0i, 0i)
+       const _ = complex(0i, 0)
+       const _ int = 1.0 + complex(1, 0i)
+
+       const _ int = complex /* ERROR int */ (1.1, 0)
+       const _ float32 = complex /* ERROR float32 */ (1, 2)
+
+       // untyped values
+       var s uint
+       _ = complex(1 /* ERROR integer */ <<s, 0)
+       const _ = complex /* ERROR not constant */ (1 /* ERROR integer */ <<s, 0)
+       var _ int = complex /* ERROR cannot use .* in variable declaration */ (1 /* ERROR integer */ <<s, 0)
+
+       // floating-point argument types must be identical
+       type F32 float32
+       type F64 float64
+       var x32 F32
+       var x64 F64
+       c64 = complex(x32, x32)
+       _ = complex(x32 /* ERROR mismatched types */ , f32)
+       _ = complex(f32 /* ERROR mismatched types */ , x32)
+       c128 = complex(x64, x64)
+       _ = c128
+       _ = complex(x64 /* ERROR mismatched types */ , f64)
+       _ = complex(f64 /* ERROR mismatched types */ , x64)
+
+       var t []float32
+       _ = complex(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func complex2() {
+       f1 := func() (x float32) { return }
+       f2 := func() (x, y float32) { return }
+       f3 := func() (x, y, z float32) { return }
+       _ = complex(f0 /* ERROR used as value */ ())
+       _ = complex(f1()) // ERROR not enough arguments
+       _ = complex(f2())
+       _ = complex(f3()) // ERROR too many arguments
+}
+
+func copy1() {
+       copy() // ERROR not enough arguments
+       copy("foo") // ERROR not enough arguments
+       copy([ /* ERROR copy expects slice arguments */ ...]int{}, []int{})
+       copy([ /* ERROR copy expects slice arguments */ ]int{}, [...]int{})
+       copy([ /* ERROR different element types */ ]int8{}, "foo")
+
+       // spec examples
+       var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
+       var s = make([]int, 6)
+       var b = make([]byte, 5)
+       n1 := copy(s, a[0:])            // n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
+       n2 := copy(s, s[2:])            // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
+       n3 := copy(b, "Hello, World!")  // n3 == 5, b == []byte("Hello")
+       _, _, _ = n1, n2, n3
+
+       var t [][]int
+       copy(t, t)
+       copy(t /* ERROR copy expects slice arguments */ , nil)
+       copy(nil /* ERROR copy expects slice arguments */ , t)
+       copy(nil /* ERROR copy expects slice arguments */ , nil)
+       copy(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func copy2() {
+       f1 := func() (a []int) { return }
+       f2 := func() (a, b []int) { return }
+       f3 := func() (a, b, c []int) { return }
+       copy(f0 /* ERROR used as value */ ())
+       copy(f1()) // ERROR not enough arguments
+       copy(f2())
+       copy(f3()) // ERROR too many arguments
+}
+
+func delete1() {
+       var m map[string]int
+       var s string
+       delete() // ERROR not enough arguments
+       delete(1) // ERROR not enough arguments
+       delete(1, 2, 3) // ERROR too many arguments
+       delete(m, 0 /* ERROR not assignable */)
+       delete(m, s)
+       _ = delete /* ERROR used as value */ (m, s)
+
+       var t []map[string]string
+       delete(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func delete2() {
+       f1 := func() (m map[string]int) { return }
+       f2 := func() (m map[string]int, k string) { return }
+       f3 := func() (m map[string]int, k string, x float32) { return }
+       delete(f0 /* ERROR used as value */ ())
+       delete(f1()) // ERROR not enough arguments
+       delete(f2())
+       delete(f3()) // ERROR too many arguments
+}
+
+func imag1() {
+       var f32 float32
+       var f64 float64
+       var c64 complex64
+       var c128 complex128
+       _ = imag() // ERROR not enough arguments
+       _ = imag(1, 2) // ERROR too many arguments
+       _ = imag(10)
+       _ = imag(2.7182818)
+       _ = imag("foo" /* ERROR expected complex */)
+       _ = imag('a')
+       const _5 = imag(1 + 2i)
+       assert(_5 == 2)
+       f32 = _5
+       f64 = _5
+       const _6 = imag(0i)
+       assert(_6 == 0)
+       f32 = imag(c64)
+       f64 = imag(c128)
+       f32 = imag /* ERROR cannot use .* in assignment */ (c128)
+       f64 = imag /* ERROR cannot use .* in assignment */ (c64)
+       imag /* ERROR not used */ (c64)
+       _, _ = f32, f64
+
+       // complex type may not be predeclared
+       type C64 complex64
+       type C128 complex128
+       var x64 C64
+       var x128 C128
+       f32 = imag(x64)
+       f64 = imag(x128)
+
+       var a []complex64
+       _ = imag(a... /* ERROR invalid use of \.\.\. */ )
+
+       // if argument is untyped, result is untyped
+       const _ byte = imag(1.2 + 3i)
+       const _ complex128 = imag(1.2 + 3i)
+
+       // lhs constant shift operands are typed as complex128
+       var s uint
+       _ = imag(1 /* ERROR must be integer */ << s)
+}
+
+func imag2() {
+       f1 := func() (x complex128) { return }
+       f2 := func() (x, y complex128) { return }
+       _ = imag(f0 /* ERROR used as value */ ())
+       _ = imag(f1())
+       _ = imag(f2()) // ERROR too many arguments
+}
+
+func len1() {
+       const c = "foobar"
+       var a [10]bool
+       var p *[20]int
+       var m map[string]complex128
+       _ = len() // ERROR not enough arguments
+       _ = len(1, 2) // ERROR too many arguments
+       _ = len(42 /* ERROR invalid */)
+       const _3 = len(c)
+       assert(_3 == 6)
+       const _4 = len(a)
+       assert(_4 == 10)
+       const _5 = len(p)
+       assert(_5 == 20)
+       _ = len(m)
+       len /* ERROR not used */ (c)
+
+       // esoteric case
+       var t string
+       var hash map[interface{}][]*[10]int
+       const n = len /* ERROR not constant */ (hash[recover()][len(t)])
+       assert(n == 10) // ok because n has unknown value and no error is reported
+       var ch <-chan int
+       const nn = len /* ERROR not constant */ (hash[<-ch][len(t)])
+
+       // issue 4744
+       type T struct{ a [10]int }
+       const _ = len(((*T)(nil)).a)
+
+       var s [][]byte
+       _ = len(s)
+       _ = len(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func len2() {
+       f1 := func() (x []int) { return }
+       f2 := func() (x, y []int) { return }
+       _ = len(f0 /* ERROR used as value */ ())
+       _ = len(f1())
+       _ = len(f2()) // ERROR too many arguments
+}
+
+// test cases for issue 7387
+func len3() {
+       var f = func() int { return 0 }
+       var x = f()
+       const (
+               _ = len([4]int{})
+               _ = len([4]int{x})
+               _ = len /* ERROR not constant */ ([4]int{f()})
+               _ = len /* ERROR not constant */ ([4]int{len([]int{})})
+               _ = len([4]int{len([4]int{})})
+       )
+       var y float64
+       var z complex128
+       const (
+               _ = len([4]float64{})
+               _ = len([4]float64{y})
+               _ = len([4]float64{real(2i)})
+               _ = len /* ERROR not constant */ ([4]float64{real(z)})
+       )
+       var ch chan [10]int
+       const (
+               _ = len /* ERROR not constant */ (<-ch)
+               _ = len /* ERROR not constant */ ([4]int{(<-ch)[0]})
+       )
+}
+
+func make1() {
+       var n int
+       var m float32
+       var s uint
+
+       _ = make() // ERROR not enough arguments
+       _ = make(1 /* ERROR not a type */)
+       _ = make(int /* ERROR cannot make */)
+
+       // slices
+       _ = make/* ERROR arguments */ ([]int)
+       _ = make/* ERROR arguments */ ([]int, 2, 3, 4)
+       _ = make([]int, int /* ERROR not an expression */)
+       _ = make([]int, 10, float32 /* ERROR not an expression */)
+       _ = make([]int, "foo" /* ERROR cannot convert */)
+       _ = make([]int, 10, 2.3 /* ERROR truncated */)
+       _ = make([]int, 5, 10.0)
+       _ = make([]int, 0i)
+       _ = make([]int, 1.0)
+       _ = make([]int, 1.0<<s)
+       _ = make([]int, 1.1 /* ERROR int */ <<s)
+       _ = make([]int, - /* ERROR must not be negative */ 1, 10)
+       _ = make([]int, 0, - /* ERROR must not be negative */ 1)
+       _ = make([]int, - /* ERROR must not be negative */ 1, - /* ERROR must not be negative */ 1)
+       _ = make([]int, 1 /* ERROR overflows */ <<100, 1 /* ERROR overflows */ <<100)
+       _ = make([]int, 10 /* ERROR length and capacity swapped */ , 9)
+       _ = make([]int, 1 /* ERROR overflows */ <<100, 12345)
+       _ = make([]int, m /* ERROR must be integer */ )
+        _ = &make /* ERROR cannot take address */ ([]int, 0)
+
+       // maps
+       _ = make /* ERROR arguments */ (map[int]string, 10, 20)
+       _ = make(map[int]float32, int /* ERROR not an expression */)
+       _ = make(map[int]float32, "foo" /* ERROR cannot convert */)
+       _ = make(map[int]float32, 10)
+       _ = make(map[int]float32, n)
+       _ = make(map[int]float32, int64(n))
+       _ = make(map[string]bool, 10.0)
+       _ = make(map[string]bool, 10.0<<s)
+        _ = &make /* ERROR cannot take address */ (map[string]bool)
+
+       // channels
+       _ = make /* ERROR arguments */ (chan int, 10, 20)
+       _ = make(chan int, int /* ERROR not an expression */)
+       _ = make(chan<- int, "foo" /* ERROR cannot convert */)
+       _ = make(chan int, - /* ERROR must not be negative */ 10)
+       _ = make(<-chan float64, 10)
+       _ = make(chan chan int, n)
+       _ = make(chan string, int64(n))
+       _ = make(chan bool, 10.0)
+       _ = make(chan bool, 10.0<<s)
+        _ = &make /* ERROR cannot take address */ (chan bool)
+
+       make /* ERROR not used */ ([]int, 10)
+
+       var t []int
+       _ = make([]int, t[0], t[1])
+       _ = make([]int, t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func make2() {
+       f1 := func() (x []int) { return }
+       _ = make(f0 /* ERROR not a type */ ())
+       _ = make(f1 /* ERROR not a type */ ())
+}
+
+func new1() {
+       _ = new() // ERROR not enough arguments
+       _ = new(1, 2) // ERROR too many arguments
+       _ = new("foo" /* ERROR not a type */)
+       p := new(float64)
+       _ = new(struct{ x, y int })
+       q := new(*float64)
+       _ = *p == **q
+       new /* ERROR not used */ (int)
+        _ = &new /* ERROR cannot take address */ (int)
+
+       _ = new(int... /* ERROR invalid use of \.\.\. */ )
+}
+
+func new2() {
+       f1 := func() (x []int) { return }
+       _ = new(f0 /* ERROR not a type */ ())
+       _ = new(f1 /* ERROR not a type */ ())
+}
+
+func panic1() {
+       panic() // ERROR not enough arguments
+       panic(1, 2) // ERROR too many arguments
+       panic(0)
+       panic("foo")
+       panic(false)
+       panic(1<<10)
+       panic(1 /* ERROR overflows */ <<1000)
+       _ = panic /* ERROR used as value */ (0)
+
+       var s []byte
+       panic(s)
+       panic(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func panic2() {
+       f1 := func() (x int) { return }
+       f2 := func() (x, y int) { return }
+       panic(f0 /* ERROR used as value */ ())
+       panic(f1())
+       panic(f2()) // ERROR too many arguments
+}
+
+func print1() {
+       print()
+       print(1)
+       print(1, 2)
+       print("foo")
+       print(2.718281828)
+       print(false)
+       print(1<<10)
+       print(1 /* ERROR overflows */ <<1000)
+       println(nil /* ERROR untyped nil */ )
+
+       var s []int
+       print(s... /* ERROR invalid use of \.\.\. */ )
+       _ = print /* ERROR used as value */ ()
+}
+
+func print2() {
+       f1 := func() (x int) { return }
+       f2 := func() (x, y int) { return }
+       f3 := func() (x int, y float32, z string) { return }
+       print(f0 /* ERROR used as value */ ())
+       print(f1())
+       print(f2())
+       print(f3())
+}
+
+func println1() {
+       println()
+       println(1)
+       println(1, 2)
+       println("foo")
+       println(2.718281828)
+       println(false)
+       println(1<<10)
+       println(1 /* ERROR overflows */ <<1000)
+       println(nil /* ERROR untyped nil */ )
+
+       var s []int
+       println(s... /* ERROR invalid use of \.\.\. */ )
+       _ = println /* ERROR used as value */ ()
+}
+
+func println2() {
+       f1 := func() (x int) { return }
+       f2 := func() (x, y int) { return }
+       f3 := func() (x int, y float32, z string) { return }
+       println(f0 /* ERROR used as value */ ())
+       println(f1())
+       println(f2())
+       println(f3())
+}
+
+func real1() {
+       var f32 float32
+       var f64 float64
+       var c64 complex64
+       var c128 complex128
+       _ = real() // ERROR not enough arguments
+       _ = real(1, 2) // ERROR too many arguments
+       _ = real(10)
+       _ = real(2.7182818)
+       _ = real("foo" /* ERROR expected complex */)
+       const _5 = real(1 + 2i)
+       assert(_5 == 1)
+       f32 = _5
+       f64 = _5
+       const _6 = real(0i)
+       assert(_6 == 0)
+       f32 = real(c64)
+       f64 = real(c128)
+       f32 = real /* ERROR cannot use .* in assignment */ (c128)
+       f64 = real /* ERROR cannot use .* in assignment */ (c64)
+       real /* ERROR not used */ (c64)
+
+       // complex type may not be predeclared
+       type C64 complex64
+       type C128 complex128
+       var x64 C64
+       var x128 C128
+       f32 = imag(x64)
+       f64 = imag(x128)
+       _, _ = f32, f64
+
+       var a []complex64
+       _ = real(a... /* ERROR invalid use of \.\.\. */ )
+
+       // if argument is untyped, result is untyped
+       const _ byte = real(1 + 2.3i)
+       const _ complex128 = real(1 + 2.3i)
+
+       // lhs constant shift operands are typed as complex128
+       var s uint
+       _ = real(1 /* ERROR must be integer */ << s)
+}
+
+func real2() {
+       f1 := func() (x complex128) { return }
+       f2 := func() (x, y complex128) { return }
+       _ = real(f0 /* ERROR used as value */ ())
+       _ = real(f1())
+       _ = real(f2()) // ERROR too many arguments
+}
+
+func recover1() {
+       _ = recover()
+       _ = recover(10) // ERROR too many arguments
+       recover()
+
+       var s []int
+       recover(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func recover2() {
+       f1 := func() (x int) { return }
+       f2 := func() (x, y int) { return }
+       _ = recover(f0 /* ERROR used as value */ ())
+       _ = recover(f1()) // ERROR too many arguments
+       _ = recover(f2()) // ERROR too many arguments
+}
+
+// assuming types.DefaultPtrSize == 8
+type S0 struct{      // offset
+       a bool       //  0
+       b rune       //  4
+       c *int       //  8
+       d bool       // 16
+       e complex128 // 24
+}                    // 40
+
+type S1 struct{   // offset
+       x float32 //  0
+       y string  //  8
+       z *S1     // 24
+       S0        // 32
+}                 // 72
+
+type S2 struct{ // offset
+       *S1     //  0
+}               //  8
+
+type S3 struct { // offset
+       a int64  //  0
+       b int32  //  8
+}                // 12
+
+type S4 struct { // offset
+       S3       //  0
+       int32    // 12
+}                // 16
+
+type S5 struct {   // offset
+       a [3]int32 //  0
+       b int32    // 12
+}                  // 16
+
+func (S2) m() {}
+
+func Alignof1() {
+       var x int
+       _ = unsafe.Alignof() // ERROR not enough arguments
+       _ = unsafe.Alignof(1, 2) // ERROR too many arguments
+       _ = unsafe.Alignof(int /* ERROR not an expression */)
+       _ = unsafe.Alignof(42)
+       _ = unsafe.Alignof(new(struct{}))
+       _ = unsafe.Alignof(1<<10)
+       _ = unsafe.Alignof(1 /* ERROR overflows */ <<1000)
+       _ = unsafe.Alignof(nil /* ERROR "untyped nil */ )
+       unsafe /* ERROR not used */ .Alignof(x)
+
+       var y S0
+       assert(unsafe.Alignof(y.a) == 1)
+       assert(unsafe.Alignof(y.b) == 4)
+       assert(unsafe.Alignof(y.c) == 8)
+       assert(unsafe.Alignof(y.d) == 1)
+       assert(unsafe.Alignof(y.e) == 8)
+
+       var s []byte
+       _ = unsafe.Alignof(s)
+       _ = unsafe.Alignof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Alignof2() {
+       f1 := func() (x int32) { return }
+       f2 := func() (x, y int32) { return }
+       _ = unsafe.Alignof(f0 /* ERROR used as value */ ())
+       assert(unsafe.Alignof(f1()) == 4)
+       _ = unsafe.Alignof(f2()) // ERROR too many arguments
+}
+
+func Offsetof1() {
+       var x struct{ f int }
+       _ = unsafe.Offsetof() // ERROR not enough arguments
+       _ = unsafe.Offsetof(1, 2) // ERROR too many arguments
+       _ = unsafe.Offsetof(int /* ERROR not a selector expression */ )
+       _ = unsafe.Offsetof(x /* ERROR not a selector expression */ )
+       _ = unsafe.Offsetof(nil /* ERROR not a selector expression */ )
+       _ = unsafe.Offsetof(x.f)
+       _ = unsafe.Offsetof((x.f))
+       _ = unsafe.Offsetof((((((((x))).f)))))
+       unsafe /* ERROR not used */ .Offsetof(x.f)
+
+       var y0 S0
+       assert(unsafe.Offsetof(y0.a) == 0)
+       assert(unsafe.Offsetof(y0.b) == 4)
+       assert(unsafe.Offsetof(y0.c) == 8)
+       assert(unsafe.Offsetof(y0.d) == 16)
+       assert(unsafe.Offsetof(y0.e) == 24)
+
+       var y1 S1
+       assert(unsafe.Offsetof(y1.x) == 0)
+       assert(unsafe.Offsetof(y1.y) == 8)
+       assert(unsafe.Offsetof(y1.z) == 24)
+       assert(unsafe.Offsetof(y1.S0) == 32)
+
+       assert(unsafe.Offsetof(y1.S0.a) == 0) // relative to S0
+       assert(unsafe.Offsetof(y1.a) == 32)   // relative to S1
+       assert(unsafe.Offsetof(y1.b) == 36)   // relative to S1
+       assert(unsafe.Offsetof(y1.c) == 40)   // relative to S1
+       assert(unsafe.Offsetof(y1.d) == 48)   // relative to S1
+       assert(unsafe.Offsetof(y1.e) == 56)   // relative to S1
+
+       var y1p *S1
+       assert(unsafe.Offsetof(y1p.S0) == 32)
+
+       type P *S1
+       var p P = y1p
+       assert(unsafe.Offsetof(p.S0) == 32)
+
+       var y2 S2
+       assert(unsafe.Offsetof(y2.S1) == 0)
+       _ = unsafe.Offsetof(y2 /* ERROR embedded via a pointer */ .x)
+       _ = unsafe.Offsetof(y2 /* ERROR method value */ .m)
+
+       var s []byte
+       _ = unsafe.Offsetof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Offsetof2() {
+       f1 := func() (x int32) { return }
+       f2 := func() (x, y int32) { return }
+       _ = unsafe.Offsetof(f0 /* ERROR not a selector expression */ ())
+       _ = unsafe.Offsetof(f1 /* ERROR not a selector expression */ ())
+       _ = unsafe.Offsetof(f2 /* ERROR not a selector expression */ ())
+}
+
+func Sizeof1() {
+       var x int
+       _ = unsafe.Sizeof() // ERROR not enough arguments
+       _ = unsafe.Sizeof(1, 2) // ERROR too many arguments
+       _ = unsafe.Sizeof(int /* ERROR not an expression */)
+       _ = unsafe.Sizeof(42)
+       _ = unsafe.Sizeof(new(complex128))
+       _ = unsafe.Sizeof(1<<10)
+       _ = unsafe.Sizeof(1 /* ERROR overflows */ <<1000)
+       _ = unsafe.Sizeof(nil /* ERROR untyped nil */ )
+       unsafe /* ERROR not used */ .Sizeof(x)
+
+       // basic types have size guarantees
+       assert(unsafe.Sizeof(byte(0)) == 1)
+       assert(unsafe.Sizeof(uint8(0)) == 1)
+       assert(unsafe.Sizeof(int8(0)) == 1)
+       assert(unsafe.Sizeof(uint16(0)) == 2)
+       assert(unsafe.Sizeof(int16(0)) == 2)
+       assert(unsafe.Sizeof(uint32(0)) == 4)
+       assert(unsafe.Sizeof(int32(0)) == 4)
+       assert(unsafe.Sizeof(float32(0)) == 4)
+       assert(unsafe.Sizeof(uint64(0)) == 8)
+       assert(unsafe.Sizeof(int64(0)) == 8)
+       assert(unsafe.Sizeof(float64(0)) == 8)
+       assert(unsafe.Sizeof(complex64(0)) == 8)
+       assert(unsafe.Sizeof(complex128(0)) == 16)
+
+       var y0 S0
+       assert(unsafe.Sizeof(y0.a) == 1)
+       assert(unsafe.Sizeof(y0.b) == 4)
+       assert(unsafe.Sizeof(y0.c) == 8)
+       assert(unsafe.Sizeof(y0.d) == 1)
+       assert(unsafe.Sizeof(y0.e) == 16)
+       assert(unsafe.Sizeof(y0) == 40)
+
+       var y1 S1
+       assert(unsafe.Sizeof(y1) == 72)
+
+       var y2 S2
+       assert(unsafe.Sizeof(y2) == 8)
+
+       var y3 S3
+       assert(unsafe.Sizeof(y3) == 12)
+
+       var y4 S4
+       assert(unsafe.Sizeof(y4) == 16)
+
+       var y5 S5
+       assert(unsafe.Sizeof(y5) == 16)
+
+       var a3 [10]S3
+       assert(unsafe.Sizeof(a3) == 156)
+
+       // test case for issue 5670
+       type T struct {
+               a int32
+               _ int32
+               c int32
+       }
+       assert(unsafe.Sizeof(T{}) == 12)
+
+       var s []byte
+       _ = unsafe.Sizeof(s)
+       _ = unsafe.Sizeof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Sizeof2() {
+       f1 := func() (x int64) { return }
+       f2 := func() (x, y int64) { return }
+       _ = unsafe.Sizeof(f0 /* ERROR used as value */ ())
+       assert(unsafe.Sizeof(f1()) == 8)
+       _ = unsafe.Sizeof(f2()) // ERROR too many arguments
+}
+
+// self-testing only
+func assert1() {
+       var x int
+       assert() /* ERROR not enough arguments */
+       assert(1, 2) /* ERROR too many arguments */
+       assert("foo" /* ERROR boolean constant */ )
+       assert(x /* ERROR boolean constant */)
+       assert(true)
+       assert /* ERROR failed */ (false)
+       _ = assert(true)
+
+       var s []byte
+       assert(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func assert2() {
+       f1 := func() (x bool) { return }
+       f2 := func() (x bool) { return }
+       assert(f0 /* ERROR used as value */ ())
+       assert(f1 /* ERROR boolean constant */ ())
+       assert(f2 /* ERROR boolean constant */ ())
+}
+
+// self-testing only
+func trace1() {
+       // Uncomment the code below to test trace - will produce console output
+       // _ = trace /* ERROR no value */ ()
+       // _ = trace(1)
+       // _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
+
+       var s []byte
+       trace(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func trace2() {
+       f1 := func() (x int) { return }
+       f2 := func() (x int, y string) { return }
+       f3 := func() (x int, y string, z []int) { return }
+       _ = f1
+       _ = f2
+       _ = f3
+       // Uncomment the code below to test trace - will produce console output
+       // trace(f0())
+       // trace(f1())
+       // trace(f2())
+       // trace(f3())
+       // trace(f0(), 1)
+       // trace(f1(), 1, 2)
+       // trace(f2(), 1, 2, 3)
+       // trace(f3(), 1, 2, 3, 4)
+}
diff --git a/src/cmd/compile/internal/types2/testdata/chans.go2 b/src/cmd/compile/internal/types2/testdata/chans.go2
new file mode 100644 (file)
index 0000000..fad2bce
--- /dev/null
@@ -0,0 +1,62 @@
+package chans
+
+import "runtime"
+
+// Ranger returns a Sender and a Receiver. The Receiver provides a
+// Next method to retrieve values. The Sender provides a Send method
+// to send values and a Close method to stop sending values. The Next
+// method indicates when the Sender has been closed, and the Send
+// method indicates when the Receiver has been freed.
+//
+// This is a convenient way to exit a goroutine sending values when
+// the receiver stops reading them.
+func Ranger[T any]() (*Sender[T], *Receiver[T]) {
+       c := make(chan T)
+       d := make(chan bool)
+       s := &Sender[T]{values: c, done: d}
+       r := &Receiver[T]{values: c, done: d}
+       runtime.SetFinalizer(r, r.finalize)
+       return s, r
+}
+
+// A sender is used to send values to a Receiver.
+type Sender[T any] struct {
+       values chan<- T
+       done <-chan bool
+}
+
+// Send sends a value to the receiver. It returns whether any more
+// values may be sent; if it returns false the value was not sent.
+func (s *Sender[T]) Send(v T) bool {
+       select {
+       case s.values <- v:
+               return true
+       case <-s.done:
+               return false
+       }
+}
+
+// Close tells the receiver that no more values will arrive.
+// After Close is called, the Sender may no longer be used.
+func (s *Sender[T]) Close() {
+       close(s.values)
+}
+
+// A Receiver receives values from a Sender.
+type Receiver[T any] struct {
+       values <-chan T
+       done chan<- bool
+}
+
+// Next returns the next value from the channel. The bool result
+// indicates whether the value is valid, or whether the Sender has
+// been closed and no more values will be received.
+func (r *Receiver[T]) Next() (T, bool) {
+       v, ok := <-r.values
+       return v, ok
+}
+
+// finalize is a finalizer for the receiver.
+func (r *Receiver[T]) finalize() {
+       close(r.done)
+}
diff --git a/src/cmd/compile/internal/types2/testdata/const0.src b/src/cmd/compile/internal/types2/testdata/const0.src
new file mode 100644 (file)
index 0000000..adbbf28
--- /dev/null
@@ -0,0 +1,350 @@
+// Copyright 2012 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.
+
+// constant declarations
+
+package const0
+
+import "unsafe"
+
+// constants declarations must be initialized by constants
+var x = 0
+const c0 = x /* ERROR "not constant" */
+
+// typed constants must have constant types
+const _ interface /* ERROR invalid constant type */ {} = 0
+
+func _ () {
+       const _ interface /* ERROR invalid constant type */ {} = 0
+       for i := 0; i < 10; i++ {} // don't crash with non-nil iota here
+}
+
+// untyped constants
+const (
+       // boolean values
+       ub0 = false
+       ub1 = true
+       ub2 = 2 < 1
+       ub3 = ui1 == uf1
+       ub4 = true /* ERROR "cannot convert" */ == 0
+
+       // integer values
+       ui0 = 0
+       ui1 = 1
+       ui2 = 42
+       ui3 = 3141592653589793238462643383279502884197169399375105820974944592307816406286
+       ui4 = -10
+
+       ui5 = ui0 + ui1
+       ui6 = ui1 - ui1
+       ui7 = ui2 * ui1
+       ui8 = ui3 / ui3
+       ui9 = ui3 % ui3
+
+       ui10 = 1 / 0 /* ERROR "division by zero" */
+       ui11 = ui1 / 0 /* ERROR "division by zero" */
+       ui12 = ui3 / ui0 /* ERROR "division by zero" */
+       ui13 = 1 % 0 /* ERROR "division by zero" */
+       ui14 = ui1 % 0 /* ERROR "division by zero" */
+       ui15 = ui3 % ui0 /* ERROR "division by zero" */
+
+       ui16 = ui2 & ui3
+       ui17 = ui2 | ui3
+       ui18 = ui2 ^ ui3
+       ui19 = 1 /* ERROR "invalid operation" */ % 1.0
+
+       // floating point values
+       uf0 = 0.
+       uf1 = 1.
+       uf2 = 4.2e1
+       uf3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
+       uf4 = 1e-1
+
+       uf5 = uf0 + uf1
+       uf6 = uf1 - uf1
+       uf7 = uf2 * uf1
+       uf8 = uf3 / uf3
+       uf9 = uf3 /* ERROR "not defined" */ % uf3
+
+       uf10 = 1 / 0 /* ERROR "division by zero" */
+       uf11 = uf1 / 0 /* ERROR "division by zero" */
+       uf12 = uf3 / uf0 /* ERROR "division by zero" */
+
+       uf16 = uf2 /* ERROR "not defined" */ & uf3
+       uf17 = uf2 /* ERROR "not defined" */ | uf3
+       uf18 = uf2 /* ERROR "not defined" */ ^ uf3
+
+       // complex values
+       uc0 = 0.i
+       uc1 = 1.i
+       uc2 = 4.2e1i
+       uc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
+       uc4 = 1e-1i
+
+       uc5 = uc0 + uc1
+       uc6 = uc1 - uc1
+       uc7 = uc2 * uc1
+       uc8 = uc3 / uc3
+       uc9 = uc3 /* ERROR "not defined" */ % uc3
+
+       uc10 = 1 / 0 /* ERROR "division by zero" */
+       uc11 = uc1 / 0 /* ERROR "division by zero" */
+       uc12 = uc3 / uc0 /* ERROR "division by zero" */
+
+       uc16 = uc2 /* ERROR "not defined" */ & uc3
+       uc17 = uc2 /* ERROR "not defined" */ | uc3
+       uc18 = uc2 /* ERROR "not defined" */ ^ uc3
+)
+
+type (
+       mybool bool
+       myint int
+       myfloat float64
+       mycomplex complex128
+)
+
+// typed constants
+const (
+       // boolean values
+       tb0 bool = false
+       tb1 bool = true
+       tb2 mybool = 2 < 1
+       tb3 mybool = ti1 /* ERROR "mismatched types" */ == tf1
+
+       // integer values
+       ti0 int8 = ui0
+       ti1 int32 = ui1
+       ti2 int64 = ui2
+       ti3 myint = ui3 /* ERROR "overflows" */
+       ti4 myint = ui4
+
+       ti5 = ti0 /* ERROR "mismatched types" */ + ti1
+       ti6 = ti1 - ti1
+       ti7 = ti2 /* ERROR "mismatched types" */ * ti1
+       ti8 = ti3 / ti3
+       ti9 = ti3 % ti3
+
+       ti10 = 1 / 0 /* ERROR "division by zero" */
+       ti11 = ti1 / 0 /* ERROR "division by zero" */
+       ti12 = ti3 /* ERROR "mismatched types" */ / ti0
+       ti13 = 1 % 0 /* ERROR "division by zero" */
+       ti14 = ti1 % 0 /* ERROR "division by zero" */
+       ti15 = ti3 /* ERROR "mismatched types" */ % ti0
+
+       ti16 = ti2 /* ERROR "mismatched types" */ & ti3
+       ti17 = ti2 /* ERROR "mismatched types" */ | ti4
+       ti18 = ti2 ^ ti5 // no mismatched types error because the type of ti5 is unknown
+
+       // floating point values
+       tf0 float32 = 0.
+       tf1 float32 = 1.
+       tf2 float64 = 4.2e1
+       tf3 myfloat = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
+       tf4 myfloat = 1e-1
+
+       tf5 = tf0 + tf1
+       tf6 = tf1 - tf1
+       tf7 = tf2 /* ERROR "mismatched types" */ * tf1
+       tf8 = tf3 / tf3
+       tf9 = tf3 /* ERROR "not defined" */ % tf3
+
+       tf10 = 1 / 0 /* ERROR "division by zero" */
+       tf11 = tf1 / 0 /* ERROR "division by zero" */
+       tf12 = tf3 /* ERROR "mismatched types" */ / tf0
+
+       tf16 = tf2 /* ERROR "mismatched types" */ & tf3
+       tf17 = tf2 /* ERROR "mismatched types" */ | tf3
+       tf18 = tf2 /* ERROR "mismatched types" */ ^ tf3
+
+       // complex values
+       tc0 = 0.i
+       tc1 = 1.i
+       tc2 = 4.2e1i
+       tc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
+       tc4 = 1e-1i
+
+       tc5 = tc0 + tc1
+       tc6 = tc1 - tc1
+       tc7 = tc2 * tc1
+       tc8 = tc3 / tc3
+       tc9 = tc3 /* ERROR "not defined" */ % tc3
+
+       tc10 = 1 / 0 /* ERROR "division by zero" */
+       tc11 = tc1 / 0 /* ERROR "division by zero" */
+       tc12 = tc3 / tc0 /* ERROR "division by zero" */
+
+       tc16 = tc2 /* ERROR "not defined" */ & tc3
+       tc17 = tc2 /* ERROR "not defined" */ | tc3
+       tc18 = tc2 /* ERROR "not defined" */ ^ tc3
+)
+
+// initialization cycles
+const (
+       a /* ERROR "initialization cycle" */ = a
+       b /* ERROR "initialization cycle" */ , c /* ERROR "initialization cycle" */, d, e = e, d, c, b // TODO(gri) should only have one cycle error
+       f float64 = d
+)
+
+// multiple initialization
+const (
+       a1, a2, a3 = 7, 3.1415926, "foo"
+       b1, b2, b3 = b3, b1, 42
+       c1, c2, c3  /* ERROR "missing init expr for c3" */ = 1, 2
+       d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */
+       _p0 = assert(a1 == 7)
+       _p1 = assert(a2 == 3.1415926)
+       _p2 = assert(a3 == "foo")
+       _p3 = assert(b1 == 42)
+       _p4 = assert(b2 == 42)
+       _p5 = assert(b3 == 42)
+)
+
+func _() {
+       const (
+               a1, a2, a3 = 7, 3.1415926, "foo"
+               b1, b2, b3 = b3, b1, 42
+               c1, c2, c3  /* ERROR "missing init expr for c3" */ = 1, 2
+               d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */
+               _p0 = assert(a1 == 7)
+               _p1 = assert(a2 == 3.1415926)
+               _p2 = assert(a3 == "foo")
+               _p3 = assert(b1 == 42)
+               _p4 = assert(b2 == 42)
+               _p5 = assert(b3 == 42)
+       )
+}
+
+// iota
+const (
+       iota0 = iota
+       iota1 = iota
+       iota2 = iota*2
+       _a0 = assert(iota0 == 0)
+       _a1 = assert(iota1 == 1)
+       _a2 = assert(iota2 == 4)
+       iota6 = iota*3
+
+       iota7
+       iota8
+       _a3 = assert(iota7 == 21)
+       _a4 = assert(iota8 == 24)
+)
+
+const (
+       _b0 = iota
+       _b1 = assert(iota + iota2 == 5)
+       _b2 = len([iota]int{}) // iota may appear in a type!
+       _b3 = assert(_b2 == 2)
+       _b4 = len(A{})
+)
+
+type A [iota /* ERROR "cannot use iota" */ ]int
+
+// constant expressions with operands across different
+// constant declarations must use the right iota values
+const (
+       _c0 = iota
+       _c1
+       _c2
+       _x = _c2 + _d1 + _e0 // 3
+)
+
+const (
+       _d0 = iota
+       _d1
+)
+
+const (
+       _e0 = iota
+)
+
+var _ = assert(_x == 3)
+
+// special cases
+const (
+       _n0 = nil /* ERROR "not constant" */
+       _n1 = [ /* ERROR "not constant" */ ]int{}
+)
+
+// iotas must not be usable in expressions outside constant declarations
+type _ [iota /* ERROR "iota outside constant decl" */ ]byte
+var _ = iota /* ERROR "iota outside constant decl" */
+func _() {
+       _ = iota /* ERROR "iota outside constant decl" */
+       const _ = iota
+       _ = iota /* ERROR "iota outside constant decl" */
+}
+
+func _() {
+       iota := 123
+       const x = iota /* ERROR "is not constant" */
+       var y = iota
+       _ = y
+}
+
+// iotas are usable inside closures in constant declarations (#22345)
+const (
+       _ = iota
+       _ = len([iota]byte{})
+       _ = unsafe.Sizeof(iota)
+       _ = unsafe.Sizeof(func() { _ = iota })
+       _ = unsafe.Sizeof(func() { var _ = iota })
+       _ = unsafe.Sizeof(func() { const _ = iota })
+       _ = unsafe.Sizeof(func() { type _ [iota]byte })
+       _ = unsafe.Sizeof(func() { func() int { return iota }() })
+)
+
+// verify inner and outer const declarations have distinct iotas
+const (
+       zero = iota
+       one  = iota
+       _    = unsafe.Sizeof(func() {
+               var x [iota]int // [2]int
+               const (
+                       Zero = iota
+                       One
+                       Two
+                       _ = unsafe.Sizeof([iota-1]int{} == x) // assert types are equal
+                       _ = unsafe.Sizeof([Two]int{} == x)    // assert types are equal
+               )
+               var z [iota]int                           // [2]int
+               _ = unsafe.Sizeof([2]int{} == z)          // assert types are equal
+       })
+       three = iota // the sequence continues
+)
+var _ [three]int = [3]int{} // assert 'three' has correct value
+
+var (
+       _ = iota /* ERROR "iota outside constant decl" */
+       _ = unsafe.Sizeof(iota  /* ERROR "iota outside constant decl" */ )
+       _ = unsafe.Sizeof(func() { _ = iota /* ERROR "iota outside constant decl" */ })
+       _ = unsafe.Sizeof(func() { var _ = iota /* ERROR "iota outside constant decl" */ })
+       _ = unsafe.Sizeof(func() { type _ [iota /* ERROR "iota outside constant decl" */ ]byte })
+       _ = unsafe.Sizeof(func() { func() int { return iota /* ERROR "iota outside constant decl" */ }() })
+)
+
+// constant arithmetic precision and rounding must lead to expected (integer) results
+var _ = []int64{
+       0.0005 * 1e9,
+       0.001 * 1e9,
+       0.005 * 1e9,
+       0.01 * 1e9,
+       0.05 * 1e9,
+       0.1 * 1e9,
+       0.5 * 1e9,
+       1 * 1e9,
+       5 * 1e9,
+}
+
+const _ = unsafe.Sizeof(func() {
+       const _ = 0
+       _ = iota
+
+       const (
+          zero = iota
+          one
+       )
+       assert(one == 1)
+       assert(iota == 0)
+})
diff --git a/src/cmd/compile/internal/types2/testdata/const1.src b/src/cmd/compile/internal/types2/testdata/const1.src
new file mode 100644 (file)
index 0000000..d827704
--- /dev/null
@@ -0,0 +1,322 @@
+// Copyright 2012 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.
+
+// constant conversions
+
+package const1
+
+const(
+       mi = ^int(0)
+       mu = ^uint(0)
+       mp = ^uintptr(0)
+
+       logSizeofInt     = uint(mi>>8&1 + mi>>16&1 + mi>>32&1)
+       logSizeofUint    = uint(mu>>8&1 + mu>>16&1 + mu>>32&1)
+       logSizeofUintptr = uint(mp>>8&1 + mp>>16&1 + mp>>32&1)
+)
+
+const (
+       minInt8 = -1<<(8<<iota - 1)
+       minInt16
+       minInt32
+       minInt64
+       minInt = -1<<(8<<logSizeofInt - 1)
+)
+
+const (
+       maxInt8 = 1<<(8<<iota - 1) - 1
+       maxInt16
+       maxInt32
+       maxInt64
+       maxInt = 1<<(8<<logSizeofInt - 1) - 1
+)
+
+const (
+       maxUint8 = 1<<(8<<iota) - 1
+       maxUint16
+       maxUint32
+       maxUint64
+       maxUint    = 1<<(8<<logSizeofUint) - 1
+       maxUintptr = 1<<(8<<logSizeofUintptr) - 1
+)
+
+const (
+       smallestFloat32 = 1.0 / (1<<(127 - 1 + 23))
+       smallestFloat64 = 1.0 / (1<<(1023 - 1 + 52))
+)
+
+const (
+       _ = assert(smallestFloat32 > 0)
+       _ = assert(smallestFloat64 > 0)
+)
+
+const (
+       maxFloat32 = 1<<127 * (1<<24 - 1) / (1.0<<23)
+       maxFloat64 = 1<<1023 * (1<<53 - 1) / (1.0<<52)
+)
+
+const (
+       _ int8 = minInt8 /* ERROR "overflows" */ - 1
+       _ int8 = minInt8
+       _ int8 = maxInt8
+       _ int8 = maxInt8 /* ERROR "overflows" */ + 1
+       _ int8 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = int8(minInt8 /* ERROR "cannot convert" */ - 1)
+       _ = int8(minInt8)
+       _ = int8(maxInt8)
+       _ = int8(maxInt8 /* ERROR "cannot convert" */ + 1)
+       _ = int8(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ int16 = minInt16 /* ERROR "overflows" */ - 1
+       _ int16 = minInt16
+       _ int16 = maxInt16
+       _ int16 = maxInt16 /* ERROR "overflows" */ + 1
+       _ int16 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = int16(minInt16 /* ERROR "cannot convert" */ - 1)
+       _ = int16(minInt16)
+       _ = int16(maxInt16)
+       _ = int16(maxInt16 /* ERROR "cannot convert" */ + 1)
+       _ = int16(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ int32 = minInt32 /* ERROR "overflows" */ - 1
+       _ int32 = minInt32
+       _ int32 = maxInt32
+       _ int32 = maxInt32 /* ERROR "overflows" */ + 1
+       _ int32 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = int32(minInt32 /* ERROR "cannot convert" */ - 1)
+       _ = int32(minInt32)
+       _ = int32(maxInt32)
+       _ = int32(maxInt32 /* ERROR "cannot convert" */ + 1)
+       _ = int32(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ int64 = minInt64 /* ERROR "overflows" */ - 1
+       _ int64 = minInt64
+       _ int64 = maxInt64
+       _ int64 = maxInt64 /* ERROR "overflows" */ + 1
+       _ int64 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = int64(minInt64 /* ERROR "cannot convert" */ - 1)
+       _ = int64(minInt64)
+       _ = int64(maxInt64)
+       _ = int64(maxInt64 /* ERROR "cannot convert" */ + 1)
+       _ = int64(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ int = minInt /* ERROR "overflows" */ - 1
+       _ int = minInt
+       _ int = maxInt
+       _ int = maxInt /* ERROR "overflows" */ + 1
+       _ int = smallestFloat64 /* ERROR "truncated" */
+
+       _ = int(minInt /* ERROR "cannot convert" */ - 1)
+       _ = int(minInt)
+       _ = int(maxInt)
+       _ = int(maxInt /* ERROR "cannot convert" */ + 1)
+       _ = int(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ uint8 = 0 /* ERROR "overflows" */ - 1
+       _ uint8 = 0
+       _ uint8 = maxUint8
+       _ uint8 = maxUint8 /* ERROR "overflows" */ + 1
+       _ uint8 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = uint8(0 /* ERROR "cannot convert" */ - 1)
+       _ = uint8(0)
+       _ = uint8(maxUint8)
+       _ = uint8(maxUint8 /* ERROR "cannot convert" */ + 1)
+       _ = uint8(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ uint16 = 0 /* ERROR "overflows" */ - 1
+       _ uint16 = 0
+       _ uint16 = maxUint16
+       _ uint16 = maxUint16 /* ERROR "overflows" */ + 1
+       _ uint16 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = uint16(0 /* ERROR "cannot convert" */ - 1)
+       _ = uint16(0)
+       _ = uint16(maxUint16)
+       _ = uint16(maxUint16 /* ERROR "cannot convert" */ + 1)
+       _ = uint16(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ uint32 = 0 /* ERROR "overflows" */ - 1
+       _ uint32 = 0
+       _ uint32 = maxUint32
+       _ uint32 = maxUint32 /* ERROR "overflows" */ + 1
+       _ uint32 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = uint32(0 /* ERROR "cannot convert" */ - 1)
+       _ = uint32(0)
+       _ = uint32(maxUint32)
+       _ = uint32(maxUint32 /* ERROR "cannot convert" */ + 1)
+       _ = uint32(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ uint64 = 0 /* ERROR "overflows" */ - 1
+       _ uint64 = 0
+       _ uint64 = maxUint64
+       _ uint64 = maxUint64 /* ERROR "overflows" */ + 1
+       _ uint64 = smallestFloat64 /* ERROR "truncated" */
+
+       _ = uint64(0 /* ERROR "cannot convert" */ - 1)
+       _ = uint64(0)
+       _ = uint64(maxUint64)
+       _ = uint64(maxUint64 /* ERROR "cannot convert" */ + 1)
+       _ = uint64(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ uint = 0 /* ERROR "overflows" */ - 1
+       _ uint = 0
+       _ uint = maxUint
+       _ uint = maxUint /* ERROR "overflows" */ + 1
+       _ uint = smallestFloat64 /* ERROR "truncated" */
+
+       _ = uint(0 /* ERROR "cannot convert" */ - 1)
+       _ = uint(0)
+       _ = uint(maxUint)
+       _ = uint(maxUint /* ERROR "cannot convert" */ + 1)
+       _ = uint(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ uintptr = 0 /* ERROR "overflows" */ - 1
+       _ uintptr = 0
+       _ uintptr = maxUintptr
+       _ uintptr = maxUintptr /* ERROR "overflows" */ + 1
+       _ uintptr = smallestFloat64 /* ERROR "truncated" */
+
+       _ = uintptr(0 /* ERROR "cannot convert" */ - 1)
+       _ = uintptr(0)
+       _ = uintptr(maxUintptr)
+       _ = uintptr(maxUintptr /* ERROR "cannot convert" */ + 1)
+       _ = uintptr(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+       _ float32 = minInt64
+       _ float64 = minInt64
+       _ complex64 = minInt64
+       _ complex128 = minInt64
+
+       _ = float32(minInt64)
+       _ = float64(minInt64)
+       _ = complex64(minInt64)
+       _ = complex128(minInt64)
+)
+
+const (
+       _ float32 = maxUint64
+       _ float64 = maxUint64
+       _ complex64 = maxUint64
+       _ complex128 = maxUint64
+
+       _ = float32(maxUint64)
+       _ = float64(maxUint64)
+       _ = complex64(maxUint64)
+       _ = complex128(maxUint64)
+)
+
+// TODO(gri) find smaller deltas below
+
+const delta32 = maxFloat32/(1 << 23)
+
+const (
+       _ float32 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
+       _ float32 = -maxFloat32
+       _ float32 = maxFloat32
+       _ float32 = maxFloat32 /* ERROR "overflow" */ + delta32
+
+       _ = float32(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
+       _ = float32(-maxFloat32)
+       _ = float32(maxFloat32)
+       _ = float32(maxFloat32 /* ERROR "cannot convert" */ + delta32)
+
+       _ = assert(float32(smallestFloat32) == smallestFloat32)
+       _ = assert(float32(smallestFloat32/2) == 0)
+       _ = assert(float32(smallestFloat64) == 0)
+       _ = assert(float32(smallestFloat64/2) == 0)
+)
+
+const delta64 = maxFloat64/(1 << 52)
+
+const (
+       _ float64 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
+       _ float64 = -maxFloat64
+       _ float64 = maxFloat64
+       _ float64 = maxFloat64 /* ERROR "overflow" */ + delta64
+
+       _ = float64(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
+       _ = float64(-maxFloat64)
+       _ = float64(maxFloat64)
+       _ = float64(maxFloat64 /* ERROR "cannot convert" */ + delta64)
+
+       _ = assert(float64(smallestFloat32) == smallestFloat32)
+       _ = assert(float64(smallestFloat32/2) == smallestFloat32/2)
+       _ = assert(float64(smallestFloat64) == smallestFloat64)
+       _ = assert(float64(smallestFloat64/2) == 0)
+)
+
+const (
+       _ complex64 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
+       _ complex64 = -maxFloat32
+       _ complex64 = maxFloat32
+       _ complex64 = maxFloat32 /* ERROR "overflow" */ + delta32
+
+       _ = complex64(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
+       _ = complex64(-maxFloat32)
+       _ = complex64(maxFloat32)
+       _ = complex64(maxFloat32 /* ERROR "cannot convert" */ + delta32)
+)
+
+const (
+       _ complex128 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
+       _ complex128 = -maxFloat64
+       _ complex128 = maxFloat64
+       _ complex128 = maxFloat64 /* ERROR "overflow" */ + delta64
+
+       _ = complex128(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
+       _ = complex128(-maxFloat64)
+       _ = complex128(maxFloat64)
+       _ = complex128(maxFloat64 /* ERROR "cannot convert" */ + delta64)
+)
+
+// Initialization of typed constant and conversion are the same:
+const (
+       f32 = 1 + smallestFloat32
+       x32 float32 = f32
+       y32 = float32(f32)
+       _ = assert(x32 - y32 == 0)
+)
+
+const (
+       f64 = 1 + smallestFloat64
+       x64 float64 = f64
+       y64 = float64(f64)
+       _ = assert(x64 - y64 == 0)
+)
+
+const (
+       _ = int8(-1) << 7
+       _ = int8 /* ERROR "overflows" */ (-1) << 8
+
+       _ = uint32(1) << 31
+       _ = uint32 /* ERROR "overflows" */ (1) << 32
+)
diff --git a/src/cmd/compile/internal/types2/testdata/constdecl.src b/src/cmd/compile/internal/types2/testdata/constdecl.src
new file mode 100644 (file)
index 0000000..1a7ed00
--- /dev/null
@@ -0,0 +1,138 @@
+// Copyright 2013 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 constdecl
+
+import "math"
+import "unsafe"
+
+var v int
+
+// Const decls must be initialized by constants.
+const _ = v /* ERROR "not constant" */
+const _ = math /* ERROR "not constant" */ .Sin(0)
+const _ = int /* ERROR "not an expression" */
+
+func _() {
+       const _ = v /* ERROR "not constant" */
+       const _ = math /* ERROR "not constant" */ .Sin(0)
+       const _ = int /* ERROR "not an expression" */
+}
+
+// Identifier and expression arity must match.
+const _ /* ERROR "missing init expr for _" */
+const _ = 1, 2 /* ERROR "extra init expr 2" */
+
+const _ /* ERROR "missing init expr for _" */ int
+const _ int = 1, 2 /* ERROR "extra init expr 2" */
+
+const (
+       _ /* ERROR "missing init expr for _" */
+       _ = 1, 2 /* ERROR "extra init expr 2" */
+
+       _ /* ERROR "missing init expr for _" */ int
+       _ int = 1, 2 /* ERROR "extra init expr 2" */
+)
+
+const (
+       _ = 1
+       _
+       _, _ /* ERROR "missing init expr for _" */
+       _
+)
+
+const (
+       _, _ = 1, 2
+       _, _
+       _ /* ERROR "extra init expr at" */
+       _, _
+       _, _, _ /* ERROR "missing init expr for _" */
+       _, _
+)
+
+func _() {
+       const _ /* ERROR "missing init expr for _" */
+       const _ = 1, 2 /* ERROR "extra init expr 2" */
+
+       const _ /* ERROR "missing init expr for _" */ int
+       const _ int = 1, 2 /* ERROR "extra init expr 2" */
+
+       const (
+               _ /* ERROR "missing init expr for _" */
+               _ = 1, 2 /* ERROR "extra init expr 2" */
+
+               _ /* ERROR "missing init expr for _" */ int
+               _ int = 1, 2 /* ERROR "extra init expr 2" */
+       )
+
+       const (
+               _ = 1
+               _
+               _, _ /* ERROR "missing init expr for _" */
+               _
+       )
+
+       const (
+               _, _ = 1, 2
+               _, _
+               _ /* ERROR "extra init expr at" */
+               _, _
+               _, _, _ /* ERROR "missing init expr for _" */
+               _, _
+       )
+}
+
+// Test case for constant with invalid initialization.
+// Caused panic because the constant value was not set up (gri - 7/8/2014).
+func _() {
+       const (
+           x string = missing /* ERROR "undeclared name" */
+           y = x + ""
+       )
+}
+
+// Test case for constants depending on function literals (see also #22992).
+const A /* ERROR initialization cycle */ = unsafe.Sizeof(func() { _ = A })
+
+func _() {
+       // The function literal below must not see a.
+       const a = unsafe.Sizeof(func() { _ = a /* ERROR "undeclared name" */ })
+       const b = unsafe.Sizeof(func() { _ = a })
+
+       // The function literal below must not see x, y, or z.
+       const x, y, z = 0, 1, unsafe.Sizeof(func() { _ = x /* ERROR "undeclared name" */ + y /* ERROR "undeclared name" */ + z /* ERROR "undeclared name" */ })
+}
+
+// Test cases for errors in inherited constant initialization expressions.
+// Errors related to inherited initialization expressions must appear at
+// the constant identifier being declared, not at the original expression
+// (issues #42991, #42992).
+const (
+       _ byte = 255 + iota
+       /* some gap */
+       _ // ERROR overflows byte
+       /* some gap */
+       /* some gap */ _ /* ERROR overflows byte */; _ /* ERROR overflows byte */
+       /* some gap */
+       _ = 255 + iota
+       _ = byte /* ERROR overflows byte */ (255) + iota
+       _ /* ERROR overflows byte */
+)
+
+// Test cases from issue.
+const (
+       ok = byte(iota + 253)
+       bad
+       barn
+       bard // ERROR cannot convert
+)
+
+const (
+       c = len([1 - iota]int{})
+       d
+       e // ERROR invalid array length
+       f // ERROR invalid array length
+)
+
+// TODO(gri) move extra tests from testdata/const0.src into here
diff --git a/src/cmd/compile/internal/types2/testdata/conversions.src b/src/cmd/compile/internal/types2/testdata/conversions.src
new file mode 100644 (file)
index 0000000..e1336c0
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2012 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.
+
+// conversions
+
+package conversions
+
+import "unsafe"
+
+// argument count
+var (
+       _ = int() /* ERROR "missing argument" */
+       _ = int(1, 2 /* ERROR "too many arguments" */ )
+)
+
+// numeric constant conversions are in const1.src.
+
+func string_conversions() {
+       const A = string(65)
+       assert(A == "A")
+       const E = string(-1)
+       assert(E == "\uFFFD")
+       assert(E == string(1234567890))
+
+       type myint int
+       assert(A == string(myint(65)))
+
+       type mystring string
+       const _ mystring = mystring("foo")
+
+       const _ = string(true /* ERROR "cannot convert" */ )
+       const _ = string(1.2 /* ERROR "cannot convert" */ )
+       const _ = string(nil /* ERROR "cannot convert" */ )
+
+       // issues 11357, 11353: argument must be of integer type
+       _ = string(0.0 /* ERROR "cannot convert" */ )
+       _ = string(0i /* ERROR "cannot convert" */ )
+       _ = string(1 /* ERROR "cannot convert" */ + 2i)
+}
+
+func interface_conversions() {
+       type E interface{}
+
+       type I1 interface{
+               m1()
+       }
+
+       type I2 interface{
+               m1()
+               m2(x int)
+       }
+
+       type I3 interface{
+               m1()
+               m2() int
+       }
+
+       var e E
+       var i1 I1
+       var i2 I2
+       var i3 I3
+
+       _ = E(0)
+       _ = E(nil)
+       _ = E(e)
+       _ = E(i1)
+       _ = E(i2)
+
+       _ = I1(0 /* ERROR "cannot convert" */ )
+       _ = I1(nil)
+       _ = I1(i1)
+       _ = I1(e /* ERROR "cannot convert" */ )
+       _ = I1(i2)
+
+       _ = I2(nil)
+       _ = I2(i1 /* ERROR "cannot convert" */ )
+       _ = I2(i2)
+       _ = I2(i3 /* ERROR "cannot convert" */ )
+
+       _ = I3(nil)
+       _ = I3(i1 /* ERROR "cannot convert" */ )
+       _ = I3(i2 /* ERROR "cannot convert" */ )
+       _ = I3(i3)
+
+       // TODO(gri) add more tests, improve error message
+}
+
+func issue6326() {
+       type T unsafe.Pointer
+       var x T
+       _ = uintptr(x) // see issue 6326
+}
diff --git a/src/cmd/compile/internal/types2/testdata/conversions2.src b/src/cmd/compile/internal/types2/testdata/conversions2.src
new file mode 100644 (file)
index 0000000..93a5f18
--- /dev/null
@@ -0,0 +1,313 @@
+// Copyright 2016 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.
+
+// Test various valid and invalid struct assignments and conversions.
+// Does not compile.
+
+package conversions2
+
+type I interface {
+       m()
+}
+
+// conversions between structs
+
+func _() {
+       type S struct{}
+       type T struct{}
+       var s S
+       var t T
+       var u struct{}
+       s = s
+       s = t // ERROR "cannot use .* in assignment"
+       s = u
+       s = S(s)
+       s = S(t)
+       s = S(u)
+       t = u
+       t = T(u)
+}
+
+func _() {
+       type S struct{ x int }
+       type T struct {
+               x int "foo"
+       }
+       var s S
+       var t T
+       var u struct {
+               x int "bar"
+       }
+       s = s
+       s = t // ERROR "cannot use .* in assignment"
+       s = u // ERROR "cannot use .* in assignment"
+       s = S(s)
+       s = S(t)
+       s = S(u)
+       t = u // ERROR "cannot use .* in assignment"
+       t = T(u)
+}
+
+func _() {
+       type E struct{ x int }
+       type S struct{ x E }
+       type T struct {
+               x E "foo"
+       }
+       var s S
+       var t T
+       var u struct {
+               x E "bar"
+       }
+       s = s
+       s = t // ERROR "cannot use .* in assignment"
+       s = u // ERROR "cannot use .* in assignment"
+       s = S(s)
+       s = S(t)
+       s = S(u)
+       t = u // ERROR "cannot use .* in assignment"
+       t = T(u)
+}
+
+func _() {
+       type S struct {
+               x struct {
+                       x int "foo"
+               }
+       }
+       type T struct {
+               x struct {
+                       x int "bar"
+               } "foo"
+       }
+       var s S
+       var t T
+       var u struct {
+               x struct {
+                       x int "bar"
+               } "bar"
+       }
+       s = s
+       s = t // ERROR "cannot use .* in assignment"
+       s = u // ERROR "cannot use .* in assignment"
+       s = S(s)
+       s = S(t)
+       s = S(u)
+       t = u // ERROR "cannot use .* in assignment"
+       t = T(u)
+}
+
+func _() {
+       type E1 struct {
+               x int "foo"
+       }
+       type E2 struct {
+               x int "bar"
+       }
+       type S struct{ x E1 }
+       type T struct {
+               x E2 "foo"
+       }
+       var s S
+       var t T
+       var u struct {
+               x E2 "bar"
+       }
+       s = s
+       s = t // ERROR "cannot use .* in assignment"
+       s = u // ERROR "cannot use .* in assignment"
+       s = S(s)
+       s = S(t /* ERROR "cannot convert" */ )
+       s = S(u /* ERROR "cannot convert" */ )
+       t = u   // ERROR "cannot use .* in assignment"
+       t = T(u)
+}
+
+func _() {
+       type E struct{ x int }
+       type S struct {
+               f func(struct {
+                       x int "foo"
+               })
+       }
+       type T struct {
+               f func(struct {
+                       x int "bar"
+               })
+       }
+       var s S
+       var t T
+       var u struct{ f func(E) }
+       s = s
+       s = t // ERROR "cannot use .* in assignment"
+       s = u // ERROR "cannot use .* in assignment"
+       s = S(s)
+       s = S(t)
+       s = S(u /* ERROR "cannot convert" */ )
+       t = u   // ERROR "cannot use .* in assignment"
+       t = T(u /* ERROR "cannot convert" */ )
+}
+
+// conversions between pointers to structs
+
+func _() {
+       type S struct{}
+       type T struct{}
+       var s *S
+       var t *T
+       var u *struct{}
+       s = s
+       s = t // ERROR "cannot use .* in assignment"
+       s = u // ERROR "cannot use .* in assignment"
+       s = (*S)(s)
+       s = (*S)(t)
+       s = (*S)(u)
+       t = u // ERROR "cannot use .* in assignment"
+       t = (*T)(u)
+}
+
+func _() {
+       type S struct{ x int }
+       type T struct {
+               x int "foo"
+       }
+       var s *S
+       var t *T
+       var u *struct {
+               x int "bar"
+       }
+       s = s
+       s = t // ERROR "cannot use .* in assignment"
+       s = u // ERROR "cannot use .* in assignment"
+       s = (*S)(s)
+       s = (*S)(t)
+       s = (*S)(u)
+       t = u // ERROR "cannot use .* in assignment"
+       t = (*T)(u)
+}
+
+func _() {
+       type E struct{ x int }
+       type S struct{ x E }
+       type T struct {
+               x E "foo"
+       }
+       var s *S
+       var t *T
+       var u *struct {
+               x E "bar"
+       }
+       s = s
+       s = t // ERROR "cannot use .* in assignment"
+       s = u // ERROR "cannot use .* in assignment"
+       s = (*S)(s)
+       s = (*S)(t)
+       s = (*S)(u)
+       t = u // ERROR "cannot use .* in assignment"
+       t = (*T)(u)
+}
+
+func _() {
+       type S struct {
+               x struct {
+                       x int "foo"
+               }
+       }
+       type T struct {
+               x struct {
+                       x int "bar"
+               } "foo"
+       }
+       var s *S
+       var t *T
+       var u *struct {
+               x struct {
+                       x int "bar"
+               } "bar"
+       }
+       s = s
+       s = t // ERROR "cannot use .* in assignment"
+       s = u // ERROR "cannot use .* in assignment"
+       s = (*S)(s)
+       s = (*S)(t)
+       s = (*S)(u)
+       t = u // ERROR "cannot use .* in assignment"
+       t = (*T)(u)
+}
+
+func _() {
+       type E1 struct {
+               x int "foo"
+       }
+       type E2 struct {
+               x int "bar"
+       }
+       type S struct{ x E1 }
+       type T struct {
+               x E2 "foo"
+       }
+       var s *S
+       var t *T
+       var u *struct {
+               x E2 "bar"
+       }
+       s = s
+       s = t // ERROR "cannot use .* in assignment"
+       s = u // ERROR "cannot use .* in assignment"
+       s = (*S)(s)
+       s = (*S)(t /* ERROR "cannot convert" */ )
+       s = (*S)(u /* ERROR "cannot convert" */ )
+       t = u      // ERROR "cannot use .* in assignment"
+       t = (*T)(u)
+}
+
+func _() {
+       type E struct{ x int }
+       type S struct {
+               f func(struct {
+                       x int "foo"
+               })
+       }
+       type T struct {
+               f func(struct {
+                       x int "bar"
+               })
+       }
+       var s *S
+       var t *T
+       var u *struct{ f func(E) }
+       s = s
+       s = t // ERROR "cannot use .* in assignment"
+       s = u // ERROR "cannot use .* in assignment"
+       s = (*S)(s)
+       s = (*S)(t)
+       s = (*S)(u /* ERROR "cannot convert" */ )
+       t = u      // ERROR "cannot use .* in assignment"
+       t = (*T)(u /* ERROR "cannot convert" */ )
+}
+
+func _() {
+       type E struct{ x int }
+       type S struct {
+               f func(*struct {
+                       x int "foo"
+               })
+       }
+       type T struct {
+               f func(*struct {
+                       x int "bar"
+               })
+       }
+       var s *S
+       var t *T
+       var u *struct{ f func(E) }
+       s = s
+       s = t // ERROR "cannot use .* in assignment"
+       s = u // ERROR "cannot use .* in assignment"
+       s = (*S)(s)
+       s = (*S)(t)
+       s = (*S)(u /* ERROR "cannot convert" */ )
+       t = u      // ERROR "cannot use .* in assignment"
+       t = (*T)(u /* ERROR "cannot convert" */ )
+}
diff --git a/src/cmd/compile/internal/types2/testdata/cycles.src b/src/cmd/compile/internal/types2/testdata/cycles.src
new file mode 100644 (file)
index 0000000..b2ee8ec
--- /dev/null
@@ -0,0 +1,174 @@
+// Copyright 2013 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 cycles
+
+import "unsafe"
+
+type (
+       T0 int
+       T1 /* ERROR cycle */ T1
+       T2 *T2
+
+       T3 /* ERROR cycle */ T4
+       T4 T5
+       T5 T3
+
+       T6 T7
+       T7 *T8
+       T8 T6
+
+       // arrays
+       A0 /* ERROR cycle */ [10]A0
+       A1 [10]*A1
+
+       A2 /* ERROR cycle */ [10]A3
+       A3 [10]A4
+       A4 A2
+
+       A5 [10]A6
+       A6 *A5
+
+       // slices
+       L0 []L0
+
+       // structs
+       S0 /* ERROR cycle */ struct{ _ S0 }
+       S1 /* ERROR cycle */ struct{ S1 }
+       S2 struct{ _ *S2 }
+       S3 struct{ *S3 }
+
+       S4 /* ERROR cycle */ struct{ S5 }
+       S5 struct{ S6 }
+       S6 S4
+
+       // pointers
+       P0 *P0
+
+       // functions
+       F0 func(F0)
+       F1 func() F1
+       F2 func(F2) F2
+
+       // interfaces
+       I0 /* ERROR cycle */ interface{ I0 }
+
+       I1 /* ERROR cycle */ interface{ I2 }
+       I2 interface{ I3 }
+       I3 interface{ I1 }
+
+       I4 interface{ f(I4) }
+
+       // testcase for issue 5090
+       I5 interface{ f(I6) }
+       I6 interface{ I5 }
+
+       // maps
+       M0 map[M0 /* ERROR invalid map key */ ]M0
+
+       // channels
+       C0 chan C0
+)
+
+// test case for issue #34771
+type (
+       AA /* ERROR cycle */ B
+       B C
+       C [10]D
+       D E
+       E AA
+)
+
+func _() {
+       type (
+               t1 /* ERROR cycle */ t1
+               t2 *t2
+
+               t3 t4 /* ERROR undeclared */
+               t4 t5 /* ERROR undeclared */
+               t5 t3
+
+               // arrays
+               a0 /* ERROR cycle */ [10]a0
+               a1 [10]*a1
+
+               // slices
+               l0 []l0
+
+               // structs
+               s0 /* ERROR cycle */ struct{ _ s0 }
+               s1 /* ERROR cycle */ struct{ s1 }
+               s2 struct{ _ *s2 }
+               s3 struct{ *s3 }
+
+               // pointers
+               p0 *p0
+
+               // functions
+               f0 func(f0)
+               f1 func() f1
+               f2 func(f2) f2
+
+               // interfaces
+               i0 /* ERROR cycle */ interface{ i0 }
+
+               // maps
+               m0 map[m0 /* ERROR invalid map key */ ]m0
+
+               // channels
+               c0 chan c0
+       )
+}
+
+// test cases for issue 6667
+
+type A [10]map[A /* ERROR invalid map key */ ]bool
+
+type S struct {
+       m map[S /* ERROR invalid map key */ ]bool
+}
+
+// test cases for issue 7236
+// (cycle detection must not be dependent on starting point of resolution)
+
+type (
+       P1 *T9
+       T9 /* ERROR cycle */ T9
+
+       T10 /* ERROR cycle */ T10
+       P2 *T10
+)
+
+func (T11) m() {}
+
+type T11 /* ERROR cycle */ struct{ T11 }
+
+type T12 /* ERROR cycle */ struct{ T12 }
+
+func (*T12) m() {}
+
+type (
+       P3 *T13
+       T13 /* ERROR cycle */ T13
+)
+
+// test cases for issue 18643
+// (type cycle detection when non-type expressions are involved)
+type (
+       T14 [len(T14 /* ERROR cycle */ {})]int
+       T15 [][len(T15 /* ERROR cycle */ {})]int
+       T16 map[[len(T16 /* ERROR cycle */ {1:2})]int]int
+       T17 map[int][len(T17 /* ERROR cycle */ {1:2})]int
+)
+
+// Test case for types depending on function literals (see also #22992).
+type T20 chan [unsafe.Sizeof(func(ch T20){ _ = <-ch })]byte
+type T22 = chan [unsafe.Sizeof(func(ch T20){ _ = <-ch })]byte
+
+func _() {
+       type T0 func(T0)
+       type T1 /* ERROR cycle */ = func(T1)
+       type T2 chan [unsafe.Sizeof(func(ch T2){ _ = <-ch })]byte
+       type T3 /* ERROR cycle */ = chan [unsafe.Sizeof(func(ch T3){ _ = <-ch })]byte
+}
diff --git a/src/cmd/compile/internal/types2/testdata/cycles1.src b/src/cmd/compile/internal/types2/testdata/cycles1.src
new file mode 100644 (file)
index 0000000..ae2b38e
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2013 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 (
+       A interface {
+               a() interface {
+                       ABC1
+               }
+       }
+       B interface {
+               b() interface {
+                       ABC2
+               }
+       }
+       C interface {
+               c() interface {
+                       ABC3
+               }
+       }
+
+       AB interface {
+               A
+               B
+       }
+       BC interface {
+               B
+               C
+       }
+
+       ABC1 interface {
+               A
+               B
+               C
+       }
+       ABC2 interface {
+               AB
+               C
+       }
+       ABC3 interface {
+               A
+               BC
+       }
+)
+
+var (
+       x1 ABC1
+       x2 ABC2
+       x3 ABC3
+)
+
+func _() {
+       // all types have the same method set
+       x1 = x2
+       x2 = x1
+
+       x1 = x3
+       x3 = x1
+
+       x2 = x3
+       x3 = x2
+
+       // all methods return the same type again
+       x1 = x1.a()
+       x1 = x1.b()
+       x1 = x1.c()
+
+       x2 = x2.a()
+       x2 = x2.b()
+       x2 = x2.c()
+
+       x3 = x3.a()
+       x3 = x3.b()
+       x3 = x3.c()
+}
diff --git a/src/cmd/compile/internal/types2/testdata/cycles2.src b/src/cmd/compile/internal/types2/testdata/cycles2.src
new file mode 100644 (file)
index 0000000..1a7f40a
--- /dev/null
@@ -0,0 +1,98 @@
+// Copyright 2013 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
+
+import "unsafe"
+
+// Test case for issue 5090
+
+type t interface {
+       f(u)
+}
+
+type u interface {
+       t
+}
+
+func _() {
+       var t t
+       var u u
+
+       t.f(t)
+       t.f(u)
+
+       u.f(t)
+       u.f(u)
+}
+
+
+// Test case for issues #6589, #33656.
+
+type A interface {
+       a() interface {
+               AB
+       }
+}
+
+type B interface {
+       b() interface {
+               AB
+       }
+}
+
+type AB interface {
+       a() interface {
+               A
+               B
+       }
+       b() interface {
+               A
+               B
+       }
+}
+
+var x AB
+var y interface {
+       A
+       B
+}
+
+var _ = x == y
+
+
+// Test case for issue 6638.
+
+type T interface {
+       m() [T(nil).m /* ERROR undefined */ ()[0]]int
+}
+
+// Variations of this test case.
+
+type T1 /* ERROR cycle */ interface {
+       m() [x1.m()[0]]int
+}
+
+var x1 T1
+
+type T2 /* ERROR cycle */ interface {
+       m() [len(x2.m())]int
+}
+
+var x2 T2
+
+type T3 /* ERROR cycle */ interface {
+       m() [unsafe.Sizeof(x3.m)]int
+}
+
+var x3 T3
+
+type T4 /* ERROR cycle */ interface {
+       m() [unsafe.Sizeof(cast4(x4.m))]int // cast is invalid but we have a cycle, so all bets are off
+}
+
+var x4 T4
+var _ = cast4(x4.m)
+
+type cast4 func()
diff --git a/src/cmd/compile/internal/types2/testdata/cycles3.src b/src/cmd/compile/internal/types2/testdata/cycles3.src
new file mode 100644 (file)
index 0000000..5e89b62
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2013 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
+
+import "unsafe"
+
+var (
+       _ A = A(nil).a().b().c().d().e().f()
+       _ A = A(nil).b().c().d().e().f()
+       _ A = A(nil).c().d().e().f()
+       _ A = A(nil).d().e().f()
+       _ A = A(nil).e().f()
+       _ A = A(nil).f()
+       _ A = A(nil)
+)
+
+type (
+       A interface {
+               a() B
+               B
+       }
+
+       B interface {
+               b() C
+               C
+       }
+
+       C interface {
+               c() D
+               D
+       }
+
+       D interface {
+               d() E
+               E
+       }
+
+       E interface {
+               e() F
+               F
+       }
+
+       F interface {
+               f() A
+       }
+)
+
+type (
+       U /* ERROR cycle */ interface {
+               V
+       }
+
+       V interface {
+               v() [unsafe.Sizeof(u)]int
+       }
+)
+
+var u U
diff --git a/src/cmd/compile/internal/types2/testdata/cycles4.src b/src/cmd/compile/internal/types2/testdata/cycles4.src
new file mode 100644 (file)
index 0000000..445babc
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright 2013 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
+
+// Check that all methods of T are collected before
+// determining the result type of m (which embeds
+// all methods of T).
+
+type T interface {
+       m() interface {T}
+       E
+}
+
+var _ = T.m(nil).m().e()
+
+type E interface {
+       e() int
+}
+
+// Check that unresolved forward chains are followed
+// (see also comment in resolver.go, checker.typeDecl).
+
+var _ = C.m(nil).m().e()
+
+type A B
+
+type B interface {
+       m() interface{C}
+       E
+}
+
+type C A
+
+// Check that interface type comparison for identity
+// does not recur endlessly.
+
+type T1 interface {
+       m() interface{T1}
+}
+
+type T2 interface {
+       m() interface{T2}
+}
+
+func _(x T1, y T2) {
+       // Checking for assignability of interfaces must check
+       // if all methods of x are present in y, and that they
+       // have identical signatures. The signatures recur via
+       // the result type, which is an interface that embeds
+       // a single method m that refers to the very interface
+       // that contains it. This requires cycle detection in
+       // identity checks for interface types.
+       x = y
+}
+
+type T3 interface {
+       m() interface{T4}
+}
+
+type T4 interface {
+       m() interface{T3}
+}
+
+func _(x T1, y T3) {
+       x = y
+}
+
+// Check that interfaces are type-checked in order of
+// (embedded interface) dependencies (was issue 7158).
+
+var x1 T5 = T7(nil)
+
+type T5 interface {
+       T6
+}
+
+type T6 interface {
+       m() T7
+}
+type T7 interface {
+       T5
+}
+
+// Actual test case from issue 7158.
+
+func wrapNode() Node {
+       return wrapElement()
+}
+
+func wrapElement() Element {
+       return nil
+}
+
+type EventTarget interface {
+       AddEventListener(Event)
+}
+
+type Node interface {
+       EventTarget
+}
+
+type Element interface {
+       Node
+}
+
+type Event interface {
+       Target() Element
+}
diff --git a/src/cmd/compile/internal/types2/testdata/cycles5.src b/src/cmd/compile/internal/types2/testdata/cycles5.src
new file mode 100644 (file)
index 0000000..397adcc
--- /dev/null
@@ -0,0 +1,200 @@
+// Copyright 2017 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
+
+import "unsafe"
+
+// test case from issue #18395
+
+type (
+       A interface { B }
+       B interface { C }
+       C interface { D; F() A }
+       D interface { G() B }
+)
+
+var _ = A(nil).G // G must be found
+
+
+// test case from issue #21804
+
+type sourceBridge interface {
+       listVersions() ([]Version, error)
+}
+
+type Constraint interface {
+       copyTo(*ConstraintMsg)
+}
+
+type ConstraintMsg struct{}
+
+func (m *ConstraintMsg) asUnpairedVersion() UnpairedVersion {
+       return nil
+}
+
+type Version interface {
+       Constraint
+}
+
+type UnpairedVersion interface {
+       Version
+}
+
+var _ Constraint = UnpairedVersion(nil)
+
+
+// derived test case from issue #21804
+
+type (
+       _ interface{ m(B1) }
+       A1 interface{ a(D1) }
+       B1 interface{ A1 }
+       C1 interface{ B1 }
+       D1 interface{ C1 }
+)
+
+var _ A1 = C1(nil)
+
+
+// derived test case from issue #22701
+
+func F(x I4) interface{} {
+       return x.Method()
+}
+
+type Unused interface {
+       RefersToI1(a I1)
+}
+
+type I1 interface {
+       I2
+       I3
+}
+
+type I2 interface {
+       RefersToI4() I4
+}
+
+type I3 interface {
+       Method() interface{}
+}
+
+type I4 interface {
+       I1
+}
+
+
+// check embedding of error interface
+
+type Error interface{ error }
+
+var err Error
+var _ = err.Error()
+
+
+// more esoteric cases
+
+type (
+       T1 interface { T2 }
+       T2 /* ERROR cycle */ T2
+)
+
+type (
+       T3 interface { T4 }
+       T4 /* ERROR cycle */ T5
+       T5 = T6
+       T6 = T7
+       T7 = T4
+)
+
+
+// arbitrary code may appear inside an interface
+
+const n = unsafe.Sizeof(func(){})
+
+type I interface {
+       m([unsafe.Sizeof(func() { I.m(nil, [n]byte{}) })]byte)
+}
+
+
+// test cases for varias alias cycles
+
+type T10 /* ERROR cycle */ = *T10                 // issue #25141
+type T11 /* ERROR cycle */ = interface{ f(T11) }  // issue #23139
+
+// issue #18640
+type (
+       aa = bb
+       bb struct {
+               *aa
+       }
+)
+
+type (
+       a struct{ *b }
+       b = c
+       c struct{ *b }
+)
+
+// issue #24939
+type (
+       _ interface {
+               M(P)
+       }
+
+       M interface {
+               F() P
+       }
+
+       P = interface {
+               I() M
+       }
+)
+
+// issue #8699
+type T12 /* ERROR cycle */ [len(a12)]int
+var a12 = makeArray()
+func makeArray() (res T12) { return }
+
+// issue #20770
+var r /* ERROR cycle */ = newReader()
+func newReader() r
+
+// variations of the theme of #8699 and #20770
+var arr /* ERROR cycle */ = f()
+func f() [len(arr)]int
+
+// issue #25790
+func ff(ff /* ERROR not a type */ )
+func gg((gg /* ERROR not a type */ ))
+
+type T13 /* ERROR cycle */ [len(b13)]int
+var b13 T13
+
+func g1() [unsafe.Sizeof(g1)]int
+func g2() [unsafe.Sizeof(x2)]int
+var x2 = g2
+
+// verify that we get the correct sizes for the functions above
+// (note: assert is statically evaluated in go/types test mode)
+func init() {
+       assert(unsafe.Sizeof(g1) == 8)
+       assert(unsafe.Sizeof(x2) == 8)
+}
+
+func h() [h /* ERROR no value */ ()[0]]int { panic(0) }
+
+var c14 /* ERROR cycle */ T14
+type T14 [uintptr(unsafe.Sizeof(&c14))]byte
+
+// issue #34333
+type T15 /* ERROR cycle */ struct {
+       f func() T16
+       b T16
+}
+
+type T16 struct {
+       T15
+}
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/testdata/decls0.src b/src/cmd/compile/internal/types2/testdata/decls0.src
new file mode 100644 (file)
index 0000000..e78d886
--- /dev/null
@@ -0,0 +1,206 @@
+// Copyright 2011 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.
+
+// type declarations
+
+package decls0
+
+import "unsafe"
+
+const pi = 3.1415
+
+type (
+       N undeclared /* ERROR "undeclared" */
+       B bool
+       I int32
+       A [10]P
+       T struct {
+               x, y P
+       }
+       P *T
+       R (*R)
+       F func(A) I
+       Y interface {
+               f(A) I
+       }
+       S [](((P)))
+       M map[I]F
+       C chan<- I
+
+       // blank types must be typechecked
+       _ pi /* ERROR "not a type" */
+       _ struct{}
+       _ struct{ pi /* ERROR "not a type" */ }
+)
+
+
+// declarations of init
+const _, init /* ERROR "cannot declare init" */ , _ = 0, 1, 2
+type init /* ERROR "cannot declare init" */ struct{}
+var _, init /* ERROR "cannot declare init" */ int
+
+func init() {}
+func init /* ERROR "missing function body" */ ()
+
+func _() { const init = 0 }
+func _() { type init int }
+func _() { var init int; _ = init }
+
+// invalid array types
+type (
+       iA0 [... /* ERROR "invalid use of \[...\] array" */ ]byte
+       // The error message below could be better. At the moment
+       // we believe an integer that is too large is not an integer.
+       // But at least we get an error.
+       iA1 [1 /* ERROR "must be integer" */ <<100]int
+       iA2 [- /* ERROR "invalid array length" */ 1]complex128
+       iA3 ["foo" /* ERROR "must be integer" */ ]string
+       iA4 [float64 /* ERROR "must be integer" */ (0)]int
+)
+
+
+type (
+       p1 pi.foo /* ERROR "no field or method foo" */
+       p2 unsafe.Pointer
+)
+
+
+type (
+       Pi pi /* ERROR "not a type" */
+
+       a /* ERROR "illegal cycle" */ a
+       a /* ERROR "redeclared" */ int
+
+       b /* ERROR "illegal cycle" */ c
+       c d
+       d e
+       e b
+
+       t *t
+
+       U V
+       V *W
+       W U
+
+       P1 *S2
+       P2 P1
+
+       S0 struct {
+       }
+       S1 struct {
+               a, b, c int
+               u, v, a /* ERROR "redeclared" */ float32
+       }
+       S2 struct {
+               S0 // embedded field
+               S0 /* ERROR "redeclared" */ int
+       }
+       S3 struct {
+               x S2
+       }
+       S4/* ERROR "illegal cycle" */ struct {
+               S4
+       }
+       S5 /* ERROR "illegal cycle" */ struct {
+               S6
+       }
+       S6 struct {
+               field S7
+       }
+       S7 struct {
+               S5
+       }
+
+       L1 []L1
+       L2 []int
+
+       A1 [10.0]int
+       A2 /* ERROR "illegal cycle" */ [10]A2
+       A3 /* ERROR "illegal cycle" */ [10]struct {
+               x A4
+       }
+       A4 [10]A3
+
+       F1 func()
+       F2 func(x, y, z float32)
+       F3 func(x, y, x /* ERROR "redeclared" */ float32)
+       F4 func() (x, y, x /* ERROR "redeclared" */ float32)
+       F5 func(x int) (x /* ERROR "redeclared" */ float32)
+       F6 func(x ...int)
+
+       I1 interface{}
+       I2 interface {
+               m1()
+       }
+       I3 interface {
+               m1()
+               m1 /* ERROR "duplicate method" */ ()
+       }
+       I4 interface {
+               m1(x, y, x /* ERROR "redeclared" */ float32)
+               m2() (x, y, x /* ERROR "redeclared" */ float32)
+               m3(x int) (x /* ERROR "redeclared" */ float32)
+       }
+       I5 interface {
+               m1(I5)
+       }
+       I6 interface {
+               S0 /* ERROR "not an interface" */
+       }
+       I7 interface {
+               I1
+               I1
+       }
+       I8 /* ERROR "illegal cycle" */ interface {
+               I8
+       }
+       I9 /* ERROR "illegal cycle" */ interface {
+               I10
+       }
+       I10 interface {
+               I11
+       }
+       I11 interface {
+               I9
+       }
+
+       C1 chan int
+       C2 <-chan int
+       C3 chan<- C3
+       C4 chan C5
+       C5 chan C6
+       C6 chan C4
+
+       M1 map[Last]string
+       M2 map[string]M2
+
+       Last int
+)
+
+// cycles in function/method declarations
+// (test cases for issues #5217, #25790 and variants)
+func f1(x f1 /* ERROR "not a type" */ ) {}
+func f2(x *f2 /* ERROR "not a type" */ ) {}
+func f3() (x f3 /* ERROR "not a type" */ ) { return }
+func f4() (x *f4 /* ERROR "not a type" */ ) { return }
+
+func (S0) m1(x S0 /* ERROR value .* is not a type */ .m1) {}
+func (S0) m2(x *S0 /* ERROR value .* is not a type */ .m2) {}
+func (S0) m3() (x S0 /* ERROR value .* is not a type */ .m3) { return }
+func (S0) m4() (x *S0 /* ERROR value .* is not a type */ .m4) { return }
+
+// interfaces may not have any blank methods
+type BlankI interface {
+       _ /* ERROR "invalid method name" */ ()
+       _ /* ERROR "invalid method name" */ (float32) int
+       m()
+}
+
+// non-interface types may have multiple blank methods
+type BlankT struct{}
+
+func (BlankT) _() {}
+func (BlankT) _(int) {}
+func (BlankT) _() int { return 0 }
+func (BlankT) _(int) int { return 0}
diff --git a/src/cmd/compile/internal/types2/testdata/decls1.src b/src/cmd/compile/internal/types2/testdata/decls1.src
new file mode 100644 (file)
index 0000000..e6beb78
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright 2012 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.
+
+// variable declarations
+
+package decls1
+
+import (
+       "math"
+)
+
+// Global variables without initialization
+var (
+       a, b bool
+       c byte
+       d uint8
+       r rune
+       i int
+       j, k, l int
+       x, y float32
+       xx, yy float64
+       u, v complex64
+       uu, vv complex128
+       s, t string
+       array []byte
+       iface interface{}
+
+       blank _ /* ERROR "cannot use _" */
+)
+
+// Global variables with initialization
+var (
+       s1 = i + j
+       s2 = i /* ERROR "mismatched types" */ + x
+       s3 = c + d
+       s4 = s + t
+       s5 = s /* ERROR "invalid operation" */ / t
+       s6 = array[t1]
+       s7 = array[x /* ERROR "integer" */]
+       s8 = &a
+       s10 = &42 /* ERROR "cannot take address" */
+       s11 = &v
+       s12 = -(u + *t11) / *&v
+       s13 = a /* ERROR "shifted operand" */ << d
+       s14 = i << j
+       s18 = math.Pi * 10.0
+       s19 = s1 /* ERROR "cannot call" */ ()
+       s20 = f0 /* ERROR "no value" */ ()
+       s21 = f6(1, s1, i)
+       s22 = f6(1, s1, uu /* ERROR "cannot use .* in argument" */ )
+
+       t1 int = i + j
+       t2 int = i /* ERROR "mismatched types" */ + x
+       t3 int = c /* ERROR "cannot use .* variable declaration" */ + d
+       t4 string = s + t
+       t5 string = s /* ERROR "invalid operation" */ / t
+       t6 byte = array[t1]
+       t7 byte = array[x /* ERROR "must be integer" */]
+       t8 *int = & /* ERROR "cannot use .* variable declaration" */ a
+       t10 *int = &42 /* ERROR "cannot take address" */
+       t11 *complex64 = &v
+       t12 complex64 = -(u + *t11) / *&v
+       t13 int = a /* ERROR "shifted operand" */ << d
+       t14 int = i << j
+       t15 math /* ERROR "not in selector" */
+       t16 math.xxx /* ERROR "not declared" */
+       t17 math /* ERROR "not a type" */ .Pi
+       t18 float64 = math.Pi * 10.0
+       t19 int = t1 /* ERROR "cannot call" */ ()
+       t20 int = f0 /* ERROR "no value" */ ()
+       t21 int = a /* ERROR "cannot use .* variable declaration" */
+)
+
+// Various more complex expressions
+var (
+       u1 = x /* ERROR "not an interface" */ .(int)
+       u2 = iface.([]int)
+       u3 = iface.(a /* ERROR "not a type" */ )
+       u4, ok = iface.(int)
+       u5, ok2, ok3 = iface /* ERROR "cannot initialize" */ .(int)
+)
+
+// Constant expression initializations
+var (
+       v1 = 1 /* ERROR "cannot convert" */ + "foo"
+       v2 = c + 255
+       v3 = c + 256 /* ERROR "overflows" */
+       v4 = r + 2147483647
+       v5 = r + 2147483648 /* ERROR "overflows" */
+       v6 = 42
+       v7 = v6 + 9223372036854775807
+       v8 = v6 + 9223372036854775808 /* ERROR "overflows" */
+       v9 = i + 1 << 10
+       v10 byte = 1024 /* ERROR "overflows" */
+       v11 = xx/yy*yy - xx
+       v12 = true && false
+       v13 = nil /* ERROR "use of untyped nil" */
+)
+
+// Multiple assignment expressions
+var (
+       m1a, m1b = 1, 2
+       m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2
+       m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */
+)
+
+func _() {
+       var (
+               m1a, m1b = 1, 2
+               m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2
+               m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */
+       )
+
+       _, _ = m1a, m1b
+       _, _, _ = m2a, m2b, m2c
+       _, _ = m3a, m3b
+}
+
+// Declaration of parameters and results
+func f0() {}
+func f1(a /* ERROR "not a type" */) {}
+func f2(a, b, c d /* ERROR "not a type" */) {}
+
+func f3() int { return 0 }
+func f4() a /* ERROR "not a type" */ { return 0 }
+func f5() (a, b, c d /* ERROR "not a type" */) { return }
+
+func f6(a, b, c int) complex128 { return 0 }
+
+// Declaration of receivers
+type T struct{}
+
+func (T) m0() {}
+func (*T) m1() {}
+func (x T) m2() {}
+func (x *T) m3() {}
+
+// Initialization functions
+func init() {}
+func /* ERROR "no arguments and no return values" */ init(int) {}
+func /* ERROR "no arguments and no return values" */ init() int { return 0 }
+func /* ERROR "no arguments and no return values" */ init(int) int { return 0 }
+func (T) init(int) int { return 0 }
diff --git a/src/cmd/compile/internal/types2/testdata/decls2/decls2a.src b/src/cmd/compile/internal/types2/testdata/decls2/decls2a.src
new file mode 100644 (file)
index 0000000..d077db5
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright 2012 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.
+
+// method declarations
+
+package decls2
+
+import "time"
+import "unsafe"
+
+// T1 declared before its methods.
+type T1 struct{
+       f int
+}
+
+func (T1) m() {}
+func (T1) m /* ERROR "already declared" */ () {}
+func (x *T1) f /* ERROR "field and method" */ () {}
+
+// Conflict between embedded field and method name,
+// with the embedded field being a basic type.
+type T1b struct {
+       int
+}
+
+func (T1b) int /* ERROR "field and method" */ () {}
+
+type T1c struct {
+       time.Time
+}
+
+func (T1c) Time /* ERROR "field and method" */ () int { return 0 }
+
+// Disabled for now: LookupFieldOrMethod will find Pointer even though
+// it's double-declared (it would cost extra in the common case to verify
+// this). But the MethodSet computation will not find it due to the name
+// collision caused by the double-declaration, leading to an internal
+// inconsistency while we are verifying one computation against the other.
+// var _ = T1c{}.Pointer
+
+// T2's method declared before the type.
+func (*T2) f /* ERROR "field and method" */ () {}
+
+type T2 struct {
+       f int
+}
+
+// Methods declared without a declared type.
+func (undeclared /* ERROR "undeclared" */) m() {}
+func (x *undeclared /* ERROR "undeclared" */) m() {}
+
+func (pi /* ERROR "not a type" */) m1() {}
+func (x pi /* ERROR "not a type" */) m2() {}
+func (x *pi /* ERROR "not a type" */ ) m3() {}
+
+// Blank types.
+type _ struct { m int }
+type _ struct { m int }
+
+func (_ /* ERROR "cannot use _" */) m() {}
+func m(_ /* ERROR "cannot use _" */) {}
+
+// Methods with receiver base type declared in another file.
+func (T3) m1() {}
+func (*T3) m2() {}
+func (x T3) m3() {}
+func (x *T3) f /* ERROR "field and method" */ () {}
+
+// Methods of non-struct type.
+type T4 func()
+
+func (self T4) m() func() { return self }
+
+// Methods associated with an interface.
+type T5 interface {
+       m() int
+}
+
+func (T5 /* ERROR "invalid receiver" */ ) m1() {}
+func (T5 /* ERROR "invalid receiver" */ ) m2() {}
+
+// Methods associated with a named pointer type.
+type ptr *int
+func (ptr /* ERROR "invalid receiver" */ ) _() {}
+func (* /* ERROR "invalid receiver" */ ptr) _() {}
+
+// Methods with zero or multiple receivers.
+func ( /* ERROR "no receiver" */ ) _() {}
+func (T3, * /* ERROR "multiple receivers" */ T3) _() {}
+func (T3, T3, T3 /* ERROR "multiple receivers" */ ) _() {}
+func (a, b /* ERROR "multiple receivers" */ T3) _() {}
+func (a, b, c /* ERROR "multiple receivers" */ T3) _() {}
+
+// Methods associated with non-local or unnamed types.
+func (int /* ERROR "invalid receiver" */ ) m() {}
+func ([ /* ERROR "invalid receiver" */ ]int) m() {}
+func (time /* ERROR "invalid receiver" */ .Time) m() {}
+func (* /* ERROR "invalid receiver" */ time.Time) m() {}
+func (x /* ERROR "invalid receiver" */ interface{}) m() {}
+
+// Unsafe.Pointer is treated like a pointer when used as receiver type.
+type UP unsafe.Pointer
+func (UP /* ERROR "invalid" */ ) m1() {}
+func (* /* ERROR "invalid" */ UP) m2() {}
+
+// Double declarations across package files
+const c_double = 0
+type t_double int
+var v_double int
+func f_double() {}
diff --git a/src/cmd/compile/internal/types2/testdata/decls2/decls2b.src b/src/cmd/compile/internal/types2/testdata/decls2/decls2b.src
new file mode 100644 (file)
index 0000000..8e82c6d
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright 2012 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.
+
+// method declarations
+
+package decls2
+
+import "io"
+
+const pi = 3.1415
+
+func (T1) m /* ERROR "already declared" */ () {}
+func (T2) m(io.Writer) {}
+
+type T3 struct {
+       f *T3
+}
+
+type T6 struct {
+       x int
+}
+
+func (t *T6) m1() int {
+       return t.x
+}
+
+func f() {
+       var t *T6
+       t.m1()
+}
+
+// Double declarations across package files
+const c_double /* ERROR "redeclared" */ = 0
+type t_double  /* ERROR "redeclared" */ int
+var v_double /* ERROR "redeclared" */ int
+func f_double /* ERROR "redeclared" */ () {}
+
+// Blank methods need to be type-checked.
+// Verify by checking that errors are reported.
+func (T /* ERROR "undeclared" */ ) _() {}
+func (T1) _(undeclared /* ERROR "undeclared" */ ) {}
+func (T1) _() int { return "foo" /* ERROR "cannot convert" */ }
+
+// Methods with undeclared receiver type can still be checked.
+// Verify by checking that errors are reported.
+func (Foo /* ERROR "undeclared" */ ) m() {}
+func (Foo /* ERROR "undeclared" */ ) m(undeclared /* ERROR "undeclared" */ ) {}
+func (Foo /* ERROR "undeclared" */ ) m() int { return "foo" /* ERROR "cannot convert" */ }
+
+func (Foo /* ERROR "undeclared" */ ) _() {}
+func (Foo /* ERROR "undeclared" */ ) _(undeclared /* ERROR "undeclared" */ ) {}
+func (Foo /* ERROR "undeclared" */ ) _() int { return "foo" /* ERROR "cannot convert" */ }
+
+// Receiver declarations are regular parameter lists;
+// receiver types may use parentheses, and the list
+// may have a trailing comma.
+type T7 struct {}
+
+func (T7) m1() {}
+func ((T7)) m2() {}
+func ((*T7)) m3() {}
+func (x *(T7),) m4() {}
+func (x (*(T7)),) m5() {}
+func (x ((*((T7)))),) m6() {}
+
+// Check that methods with parenthesized receiver are actually present (issue #23130).
+var (
+       _ = T7.m1
+       _ = T7.m2
+       _ = (*T7).m3
+       _ = (*T7).m4
+       _ = (*T7).m5
+       _ = (*T7).m6
+)
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/testdata/decls3.src b/src/cmd/compile/internal/types2/testdata/decls3.src
new file mode 100644 (file)
index 0000000..d7a0c44
--- /dev/null
@@ -0,0 +1,309 @@
+// Copyright 2012 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.
+
+// embedded types
+
+package decls3
+
+import "unsafe"
+import "fmt"
+
+// fields with the same name at the same level cancel each other out
+
+func _() {
+       type (
+               T1 struct { X int }
+               T2 struct { X int }
+               T3 struct { T1; T2 } // X is embedded twice at the same level via T1->X, T2->X
+       )
+
+       var t T3
+       _ = t.X /* ERROR "ambiguous selector t.X" */
+}
+
+func _() {
+       type (
+               T1 struct { X int }
+               T2 struct { T1 }
+               T3 struct { T1 }
+               T4 struct { T2; T3 } // X is embedded twice at the same level via T2->T1->X, T3->T1->X
+       )
+
+       var t T4
+       _ = t.X /* ERROR "ambiguous selector t.X" */
+}
+
+func issue4355() {
+       type (
+           T1 struct {X int}
+           T2 struct {T1}
+           T3 struct {T2}
+           T4 struct {T2}
+           T5 struct {T3; T4} // X is embedded twice at the same level via T3->T2->T1->X, T4->T2->T1->X
+       )
+
+       var t T5
+       _ = t.X /* ERROR "ambiguous selector t.X" */
+}
+
+func _() {
+       type State int
+       type A struct{ State }
+       type B struct{ fmt.State }
+       type T struct{ A; B }
+
+       var t T
+       _ = t.State /* ERROR "ambiguous selector t.State" */
+}
+
+// Embedded fields can be predeclared types.
+
+func _() {
+       type T0 struct{
+               int
+               float32
+               f int
+       }
+       var x T0
+       _ = x.int
+       _ = x.float32
+       _ = x.f
+
+       type T1 struct{
+               T0
+       }
+       var y T1
+       _ = y.int
+       _ = y.float32
+       _ = y.f
+}
+
+// Restrictions on embedded field types.
+
+func _() {
+       type I1 interface{}
+       type I2 interface{}
+       type P1 *int
+       type P2 *int
+       type UP unsafe.Pointer
+
+       type T1 struct {
+               I1
+               * /* ERROR "cannot be a pointer to an interface" */ I2
+               * /* ERROR "cannot be a pointer to an interface" */ error
+               P1 /* ERROR "cannot be a pointer" */
+               * /* ERROR "cannot be a pointer" */ P2
+       }
+
+       // unsafe.Pointers are treated like regular pointers when embedded
+       type T2 struct {
+               unsafe /* ERROR "cannot be unsafe.Pointer" */ .Pointer
+               */* ERROR "cannot be unsafe.Pointer" */ /* ERROR "Pointer redeclared" */ unsafe.Pointer
+               UP /* ERROR "cannot be unsafe.Pointer" */
+               * /* ERROR "cannot be unsafe.Pointer" */  /* ERROR "UP redeclared" */ UP
+       }
+}
+
+// Named types that are pointers.
+
+type S struct{ x int }
+func (*S) m() {}
+type P *S
+
+func _() {
+       var s *S
+       _ = s.x
+       _ = s.m
+
+       var p P
+       _ = p.x
+       _ = p.m /* ERROR "no field or method" */
+       _ = P.m /* ERROR "no field or method" */
+}
+
+// Borrowed from the FieldByName test cases in reflect/all_test.go.
+
+type D1 struct {
+       d int
+}
+type D2 struct {
+       d int
+}
+
+type S0 struct {
+       A, B, C int
+       D1
+       D2
+}
+
+type S1 struct {
+       B int
+       S0
+}
+
+type S2 struct {
+       A int
+       *S1
+}
+
+type S1x struct {
+       S1
+}
+
+type S1y struct {
+       S1
+}
+
+type S3 struct {
+       S1x
+       S2
+       D, E int
+       *S1y
+}
+
+type S4 struct {
+       *S4
+       A int
+}
+
+// The X in S6 and S7 annihilate, but they also block the X in S8.S9.
+type S5 struct {
+       S6
+       S7
+       S8
+}
+
+type S6 struct {
+       X int
+}
+
+type S7 S6
+
+type S8 struct {
+       S9
+}
+
+type S9 struct {
+       X int
+       Y int
+}
+
+// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9.
+type S10 struct {
+       S11
+       S12
+       S13
+}
+
+type S11 struct {
+       S6
+}
+
+type S12 struct {
+       S6
+}
+
+type S13 struct {
+       S8
+}
+
+func _() {
+       _ = struct{}{}.Foo /* ERROR "no field or method" */
+       _ = S0{}.A
+       _ = S0{}.D /* ERROR "no field or method" */
+       _ = S1{}.A
+       _ = S1{}.B
+       _ = S1{}.S0
+       _ = S1{}.C
+       _ = S2{}.A
+       _ = S2{}.S1
+       _ = S2{}.B
+       _ = S2{}.C
+       _ = S2{}.D /* ERROR "no field or method" */
+       _ = S3{}.S1 /* ERROR "ambiguous selector S3\{\}.S1" */
+       _ = S3{}.A
+       _ = S3{}.B /* ERROR "ambiguous selector" S3\{\}.B */
+       _ = S3{}.D
+       _ = S3{}.E
+       _ = S4{}.A
+       _ = S4{}.B /* ERROR "no field or method" */
+       _ = S5{}.X /* ERROR "ambiguous selector S5\{\}.X" */
+       _ = S5{}.Y
+       _ = S10{}.X /* ERROR "ambiguous selector S10\{\}.X" */
+       _ = S10{}.Y
+}
+
+// Borrowed from the FieldByName benchmark in reflect/all_test.go.
+
+type R0 struct {
+       *R1
+       *R2
+       *R3
+       *R4
+}
+
+type R1 struct {
+       *R5
+       *R6
+       *R7
+       *R8
+}
+
+type R2 R1
+type R3 R1
+type R4 R1
+
+type R5 struct {
+       *R9
+       *R10
+       *R11
+       *R12
+}
+
+type R6 R5
+type R7 R5
+type R8 R5
+
+type R9 struct {
+       *R13
+       *R14
+       *R15
+       *R16
+}
+
+type R10 R9
+type R11 R9
+type R12 R9
+
+type R13 struct {
+       *R17
+       *R18
+       *R19
+       *R20
+}
+
+type R14 R13
+type R15 R13
+type R16 R13
+
+type R17 struct {
+       *R21
+       *R22
+       *R23
+       *R24
+}
+
+type R18 R17
+type R19 R17
+type R20 R17
+
+type R21 struct {
+       X int
+}
+
+type R22 R21
+type R23 R21
+type R24 R21
+
+var _ = R0{}.X /* ERROR "ambiguous selector R0\{\}.X" */
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/testdata/decls4.src b/src/cmd/compile/internal/types2/testdata/decls4.src
new file mode 100644 (file)
index 0000000..eb08421
--- /dev/null
@@ -0,0 +1,199 @@
+// Copyright 2016 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.
+
+// type aliases
+
+package decls4
+
+type (
+       T0 [10]int
+       T1 []byte
+       T2 struct {
+               x int
+       }
+       T3 interface{
+               m() T2
+       }
+       T4 func(int, T0) chan T2
+)
+
+type (
+       Ai = int
+       A0 = T0
+       A1 = T1
+       A2 = T2
+       A3 = T3
+       A4 = T4
+
+       A10 = [10]int
+       A11 = []byte
+       A12 = struct {
+               x int
+       }
+       A13 = interface{
+               m() A2
+       }
+       A14 = func(int, A0) chan A2
+)
+
+// check assignment compatibility due to equality of types
+var (
+       xi_ int
+       ai Ai = xi_
+
+       x0 T0
+       a0 A0 = x0
+
+       x1 T1
+       a1 A1 = x1
+
+       x2 T2
+       a2 A2 = x2
+
+       x3 T3
+       a3 A3 = x3
+
+       x4 T4
+       a4 A4 = x4
+)
+
+// alias receiver types
+func (Ai /* ERROR "invalid receiver" */) m1() {}
+func (T0) m1() {}
+func (A0) m1 /* ERROR already declared */ () {}
+func (A0) m2 () {}
+func (A3 /* ERROR invalid receiver */ ) m1 () {}
+func (A10 /* ERROR invalid receiver */ ) m1() {}
+
+// x0 has methods m1, m2 declared via receiver type names T0 and A0
+var _ interface{ m1(); m2() } = x0
+
+// alias receiver types (test case for issue #23042)
+type T struct{}
+
+var (
+       _ = T.m
+       _ = T{}.m
+       _ interface{m()} = T{}
+)
+
+var (
+       _ = T.n
+       _ = T{}.n
+       _ interface{m(); n()} = T{}
+)
+
+type U = T
+func (U) m() {}
+
+// alias receiver types (long type declaration chains)
+type (
+       V0 = V1
+       V1 = (V2)
+       V2 = ((V3))
+       V3 = T
+)
+
+func (V0) m /* ERROR already declared */ () {}
+func (V1) n() {}
+
+// alias receiver types (invalid due to cycles)
+type (
+       W0 /* ERROR illegal cycle */ = W1
+       W1 = (W2)
+       W2 = ((W0))
+)
+
+func (W0) m() {} // no error expected (due to above cycle error)
+func (W1) n() {}
+
+// alias receiver types (invalid due to builtin underlying type)
+type (
+       B0 = B1
+       B1 = B2
+       B2 = int
+)
+
+func (B0 /* ERROR invalid receiver */ ) m() {}
+func (B1 /* ERROR invalid receiver */ ) n() {}
+
+// cycles
+type (
+       C2 /* ERROR illegal cycle */ = C2
+       C3 /* ERROR illegal cycle */ = C4
+       C4 = C3
+       C5 struct {
+               f *C6
+       }
+       C6 = C5
+       C7 /* ERROR illegal cycle */  struct {
+               f C8
+       }
+       C8 = C7
+)
+
+// embedded fields
+var (
+       s0 struct { T0 }
+       s1 struct { A0 } = s0 /* ERROR cannot use */ // embedded field names are different
+)
+
+// embedding and lookup of fields and methods
+func _(s struct{A0}) { s.A0 = x0 }
+
+type eX struct{xf int}
+
+func (eX) xm()
+
+type eY = struct{eX} // field/method set of eY includes xf, xm
+
+type eZ = *struct{eX} // field/method set of eZ includes xf, xm
+
+type eA struct {
+       eX // eX contributes xf, xm to eA
+}
+
+type eA2 struct {
+       *eX // *eX contributes xf, xm to eA
+}
+
+type eB struct {
+       eY // eY contributes xf, xm to eB
+}
+
+type eB2 struct {
+       *eY // *eY contributes xf, xm to eB
+}
+
+type eC struct {
+       eZ // eZ contributes xf, xm to eC
+}
+
+var (
+       _ = eA{}.xf
+       _ = eA{}.xm
+       _ = eA2{}.xf
+       _ = eA2{}.xm
+       _ = eB{}.xf
+       _ = eB{}.xm
+       _ = eB2{}.xf
+       _ = eB2{}.xm
+       _ = eC{}.xf
+       _ = eC{}.xm
+)
+
+// ambiguous selectors due to embedding via type aliases
+type eD struct {
+       eY
+       eZ
+}
+
+var (
+       _ = eD{}.xf /* ERROR ambiguous selector eD\{\}.xf */
+       _ = eD{}.xm /* ERROR ambiguous selector eD\{\}.xm */
+)
+
+var (
+       _ interface{ xm() } = eD /* ERROR missing method xm */ {}
+)
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/testdata/decls5.src b/src/cmd/compile/internal/types2/testdata/decls5.src
new file mode 100644 (file)
index 0000000..88d3194
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2017 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
+
+// declarations of main
+const _, main /* ERROR "cannot declare main" */ , _ = 0, 1, 2
+type main /* ERROR "cannot declare main" */ struct{}
+var _, main /* ERROR "cannot declare main" */ int
diff --git a/src/cmd/compile/internal/types2/testdata/errors.src b/src/cmd/compile/internal/types2/testdata/errors.src
new file mode 100644 (file)
index 0000000..ff92921
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2013 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 errors
+
+// Testing precise operand formatting in error messages
+// (matching messages are regular expressions, hence the \'s).
+func f(x int, m map[string]int) {
+       // no values
+       _ = f /* ERROR "f\(0, m\) \(no value\) used as value" */ (0, m)
+
+       // built-ins
+       _ = println /* ERROR "println \(built-in\) must be called" */
+
+       // types
+       _ = complex128 /* ERROR "complex128 \(type\) is not an expression" */
+
+       // constants
+       const c1 = 991
+       const c2 float32 = 0.5
+       0 /* ERROR "0 \(untyped int constant\) is not used" */
+       c1 /* ERROR "c1 \(untyped int constant 991\) is not used" */
+       c2 /* ERROR "c2 \(constant 0.5 of type float32\) is not used" */
+       c1 /* ERROR "c1 \+ c2 \(constant 991.5 of type float32\) is not used" */ + c2
+
+       // variables
+       x /* ERROR "x \(variable of type int\) is not used" */
+
+       // values
+       x /* ERROR "x != x \(untyped bool value\) is not used" */ != x
+       x /* ERROR "x \+ x \(value of type int\) is not used" */ + x
+
+       // value, ok's
+       const s = "foo"
+       m /* ERROR "m\[s\] \(map index expression of type int\) is not used" */ [s]
+}
+
+// Valid ERROR comments can have a variety of forms.
+func _() {
+       0 /* ERROR "0 .* is not used" */
+       0 /* ERROR 0 .* is not used */
+       0 // ERROR "0 .* is not used"
+       0 // ERROR 0 .* is not used
+}
+
+// Don't report spurious errors as a consequence of earlier errors.
+// Add more tests as needed.
+func _() {
+       if err := foo /* ERROR undeclared */ (); err != nil /* no error here */ {}
+}
+
+// Use unqualified names for package-local objects.
+type T struct{}
+var _ int = T /* ERROR value of type T */ {} // use T in error message rather then errors.T
+
+// Don't report errors containing "invalid type" (issue #24182).
+func _(x *missing /* ERROR undeclared name: missing */ ) {
+       x.m() // there shouldn't be an error here referring to *invalid type
+}
diff --git a/src/cmd/compile/internal/types2/testdata/expr0.src b/src/cmd/compile/internal/types2/testdata/expr0.src
new file mode 100644 (file)
index 0000000..1aac726
--- /dev/null
@@ -0,0 +1,180 @@
+// Copyright 2012 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.
+
+// unary expressions
+
+package expr0 
+
+type mybool bool
+
+var (
+       // bool
+       b0 = true
+       b1 bool = b0
+       b2 = !true
+       b3 = !b1
+       b4 bool = !true
+       b5 bool = !b4
+       b6 = +b0 /* ERROR "not defined" */
+       b7 = -b0 /* ERROR "not defined" */
+       b8 = ^b0 /* ERROR "not defined" */
+       b9 = *b0 /* ERROR "cannot indirect" */
+       b10 = &true /* ERROR "cannot take address" */
+       b11 = &b0
+       b12 = <-b0 /* ERROR "cannot receive" */
+       b13 = & & /* ERROR "cannot take address" */ b0
+
+       // byte
+       _ = byte(0)
+       _ = byte(- /* ERROR "cannot convert" */ 1)
+       _ = - /* ERROR "-byte\(1\) \(constant -1 of type byte\) overflows byte" */ byte(1) // test for issue 11367
+       _ = byte /* ERROR "overflows byte" */ (0) - byte(1)
+
+       // int
+       i0 = 1
+       i1 int = i0
+       i2 = +1
+       i3 = +i0
+       i4 int = +1
+       i5 int = +i4
+       i6 = -1
+       i7 = -i0
+       i8 int = -1
+       i9 int = -i4
+       i10 = !i0 /* ERROR "not defined" */
+       i11 = ^1
+       i12 = ^i0
+       i13 int = ^1
+       i14 int = ^i4
+       i15 = *i0 /* ERROR "cannot indirect" */
+       i16 = &i0
+       i17 = *i16
+       i18 = <-i16 /* ERROR "cannot receive" */
+
+       // uint
+       u0 = uint(1)
+       u1 uint = u0
+       u2 = +1
+       u3 = +u0
+       u4 uint = +1
+       u5 uint = +u4
+       u6 = -1
+       u7 = -u0
+       u8 uint = - /* ERROR "overflows" */ 1
+       u9 uint = -u4
+       u10 = !u0 /* ERROR "not defined" */
+       u11 = ^1
+       u12 = ^i0
+       u13 uint = ^ /* ERROR "overflows" */ 1
+       u14 uint = ^u4
+       u15 = *u0 /* ERROR "cannot indirect" */
+       u16 = &u0
+       u17 = *u16
+       u18 = <-u16 /* ERROR "cannot receive" */
+       u19 = ^uint(0)
+
+       // float64
+       f0 = float64(1)
+       f1 float64 = f0
+       f2 = +1
+       f3 = +f0
+       f4 float64 = +1
+       f5 float64 = +f4
+       f6 = -1
+       f7 = -f0
+       f8 float64 = -1
+       f9 float64 = -f4
+       f10 = !f0 /* ERROR "not defined" */
+       f11 = ^1
+       f12 = ^i0
+       f13 float64 = ^1
+       f14 float64 = ^f4 /* ERROR "not defined" */
+       f15 = *f0 /* ERROR "cannot indirect" */
+       f16 = &f0
+       f17 = *u16
+       f18 = <-u16 /* ERROR "cannot receive" */
+
+       // complex128
+       c0 = complex128(1)
+       c1 complex128 = c0
+       c2 = +1
+       c3 = +c0
+       c4 complex128 = +1
+       c5 complex128 = +c4
+       c6 = -1
+       c7 = -c0
+       c8 complex128 = -1
+       c9 complex128 = -c4
+       c10 = !c0 /* ERROR "not defined" */
+       c11 = ^1
+       c12 = ^i0
+       c13 complex128 = ^1
+       c14 complex128 = ^c4 /* ERROR "not defined" */
+       c15 = *c0 /* ERROR "cannot indirect" */
+       c16 = &c0
+       c17 = *u16
+       c18 = <-u16 /* ERROR "cannot receive" */
+
+       // string
+       s0 = "foo"
+       s1 = +"foo" /* ERROR "not defined" */
+       s2 = -s0 /* ERROR "not defined" */
+       s3 = !s0 /* ERROR "not defined" */
+       s4 = ^s0 /* ERROR "not defined" */
+       s5 = *s4
+       s6 = &s4
+       s7 = *s6
+       s8 = <-s7
+
+       // channel
+       ch chan int
+       rc <-chan float64
+       sc chan <- string
+       ch0 = +ch /* ERROR "not defined" */
+       ch1 = -ch /* ERROR "not defined" */
+       ch2 = !ch /* ERROR "not defined" */
+       ch3 = ^ch /* ERROR "not defined" */
+       ch4 = *ch /* ERROR "cannot indirect" */
+       ch5 = &ch
+       ch6 = *ch5
+       ch7 = <-ch
+       ch8 = <-rc
+       ch9 = <-sc /* ERROR "cannot receive" */
+       ch10, ok = <-ch
+       // ok is of type bool
+       ch11, myok = <-ch
+       _ mybool = myok /* ERROR "cannot use .* in variable declaration" */
+)
+
+// address of composite literals
+type T struct{x, y int}
+
+func f() T { return T{} }
+
+var (
+       _ = &T{1, 2}
+       _ = &[...]int{}
+       _ = &[]int{}
+       _ = &[]int{}
+       _ = &map[string]T{}
+       _ = &(T{1, 2})
+       _ = &((((T{1, 2}))))
+       _ = &f /* ERROR "cannot take address" */ ()
+)
+
+// recursive pointer types
+type P *P
+
+var (
+       p1 P = new(P)
+       p2 P = *p1
+       p3 P = &p2
+)
+
+func g() (a, b int) { return }
+
+func _() {
+       _ = -g /* ERROR 2-valued g */ ()
+       _ = <-g /* ERROR 2-valued g */ ()
+}
diff --git a/src/cmd/compile/internal/types2/testdata/expr1.src b/src/cmd/compile/internal/types2/testdata/expr1.src
new file mode 100644 (file)
index 0000000..4ead815
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright 2012 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.
+
+// binary expressions
+
+package expr1
+
+type mybool bool
+
+func _(x, y bool, z mybool) {
+       x = x || y
+       x = x || true
+       x = x || false
+       x = x && y
+       x = x && true
+       x = x && false
+
+       z = z /* ERROR mismatched types */ || y
+       z = z || true
+       z = z || false
+       z = z /* ERROR mismatched types */ && y
+       z = z && true
+       z = z && false
+}
+
+type myint int
+
+func _(x, y int, z myint) {
+       x = x + 1
+       x = x + 1.0
+       x = x + 1.1 // ERROR truncated to int
+       x = x + y
+       x = x - y
+       x = x * y
+       x = x / y
+       x = x % y
+       x = x << y
+       x = x >> y
+
+       z = z + 1
+       z = z + 1.0
+       z = z + 1.1 // ERROR truncated to int
+       z = z /* ERROR mismatched types */ + y
+       z = z /* ERROR mismatched types */ - y
+       z = z /* ERROR mismatched types */ * y
+       z = z /* ERROR mismatched types */ / y
+       z = z /* ERROR mismatched types */ % y
+       z = z << y
+       z = z >> y
+}
+
+type myuint uint
+
+func _(x, y uint, z myuint) {
+       x = x + 1
+       x = x + - /* ERROR overflows uint */ 1
+       x = x + 1.0
+       x = x + 1.1 // ERROR truncated to uint
+       x = x + y
+       x = x - y
+       x = x * y
+       x = x / y
+       x = x % y
+       x = x << y
+       x = x >> y
+
+       z = z + 1
+       z = x + - /* ERROR overflows uint */ 1
+       z = z + 1.0
+       z = z + 1.1 // ERROR truncated to uint
+       z = z /* ERROR mismatched types */ + y
+       z = z /* ERROR mismatched types */ - y
+       z = z /* ERROR mismatched types */ * y
+       z = z /* ERROR mismatched types */ / y
+       z = z /* ERROR mismatched types */ % y
+       z = z << y
+       z = z >> y
+}
+
+type myfloat64 float64
+
+func _(x, y float64, z myfloat64) {
+       x = x + 1
+       x = x + -1
+       x = x + 1.0
+       x = x + 1.1
+       x = x + y
+       x = x - y
+       x = x * y
+       x = x / y
+       x = x /* ERROR not defined */ % y
+       x = x /* ERROR operand x .* must be integer */ << y
+       x = x /* ERROR operand x .* must be integer */ >> y
+
+       z = z + 1
+       z = z + -1
+       z = z + 1.0
+       z = z + 1.1
+       z = z /* ERROR mismatched types */ + y
+       z = z /* ERROR mismatched types */ - y
+       z = z /* ERROR mismatched types */ * y
+       z = z /* ERROR mismatched types */ / y
+       z = z /* ERROR mismatched types */ % y
+       z = z /* ERROR operand z .* must be integer */ << y
+       z = z /* ERROR operand z .* must be integer */ >> y
+}
+
+type mystring string
+
+func _(x, y string, z mystring) {
+       x = x + "foo"
+       x = x /* ERROR not defined */ - "foo"
+       x = x + 1 // ERROR cannot convert
+       x = x + y
+       x = x /* ERROR not defined */ - y
+       x = x * 10 // ERROR cannot convert
+}
+
+func f() (a, b int) { return }
+
+func _(x int) {
+       _ = f /* ERROR 2-valued f */ () + 1
+       _ = x + f /* ERROR 2-valued f */ ()
+       _ = f /* ERROR 2-valued f */ () + f
+       _ = f /* ERROR 2-valued f */ () + f /* ERROR 2-valued f */ ()
+}
diff --git a/src/cmd/compile/internal/types2/testdata/expr2.src b/src/cmd/compile/internal/types2/testdata/expr2.src
new file mode 100644 (file)
index 0000000..0c959e8
--- /dev/null
@@ -0,0 +1,260 @@
+// Copyright 2012 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.
+
+// comparisons
+
+package expr2
+
+func _bool() {
+       const t = true == true
+       const f = true == false
+       _ = t /* ERROR "cannot compare" */ < f
+       _ = 0 /* ERROR "cannot convert" */ == t
+       var b bool
+       var x, y float32
+       b = x < y
+       _ = b
+       _ = struct{b bool}{x < y}
+}
+
+// corner cases
+var (
+       v0 = nil /* ERROR "cannot compare" */ == nil
+)
+
+func arrays() {
+       // basics
+       var a, b [10]int
+       _ = a == b
+       _ = a != b
+       _ = a /* ERROR < not defined */ < b
+       _ = a == nil /* ERROR cannot convert */
+
+       type C [10]int
+       var c C
+       _ = a == c
+
+       type D [10]int
+       var d D
+       _ = c /* ERROR mismatched types */ == d
+
+       var e [10]func() int
+       _ = e /* ERROR == not defined */ == e
+}
+
+func structs() {
+       // basics
+       var s, t struct {
+               x int
+               a [10]float32
+               _ bool
+       }
+       _ = s == t
+       _ = s != t
+       _ = s /* ERROR < not defined */ < t
+       _ = s == nil /* ERROR cannot convert */
+
+       type S struct {
+               x int
+               a [10]float32
+               _ bool
+       }
+       type T struct {
+               x int
+               a [10]float32
+               _ bool
+       }
+       var ss S
+       var tt T
+       _ = s == ss
+       _ = ss /* ERROR mismatched types */ == tt
+
+       var u struct {
+               x int
+               a [10]map[string]int
+       }
+       _ = u /* ERROR cannot compare */ == u
+}
+
+func pointers() {
+       // nil
+       _ = nil /* ERROR == not defined */ == nil
+       _ = nil /* ERROR != not defined */ != nil
+       _ = nil /* ERROR < not defined */ < nil
+       _ = nil /* ERROR <= not defined */ <= nil
+       _ = nil /* ERROR > not defined */ > nil
+       _ = nil /* ERROR >= not defined */ >= nil
+
+       // basics
+       var p, q *int
+       _ = p == q
+       _ = p != q
+
+       _ = p == nil
+       _ = p != nil
+       _ = nil == q
+       _ = nil != q
+
+       _ = p /* ERROR < not defined */ < q
+       _ = p /* ERROR <= not defined */ <= q
+       _ = p /* ERROR > not defined */ > q
+       _ = p /* ERROR >= not defined */ >= q
+
+       // various element types
+       type (
+               S1 struct{}
+               S2 struct{}
+               P1 *S1
+               P2 *S2
+       )
+       var (
+               ps1 *S1
+               ps2 *S2
+               p1 P1
+               p2 P2
+       )
+       _ = ps1 == ps1
+       _ = ps1 /* ERROR mismatched types */ == ps2
+       _ = ps2 /* ERROR mismatched types */ == ps1
+
+       _ = p1 == p1
+       _ = p1 /* ERROR mismatched types */ == p2
+
+       _ = p1 == ps1
+}
+
+func channels() {
+       // basics
+       var c, d chan int
+       _ = c == d
+       _ = c != d
+       _ = c == nil
+       _ = c /* ERROR < not defined */ < d
+
+       // various element types (named types)
+       type (
+               C1 chan int
+               C1r <-chan int
+               C1s chan<- int
+               C2 chan float32
+       )
+       var (
+               c1 C1
+               c1r C1r
+               c1s C1s
+               c1a chan int
+               c2 C2
+       )
+       _ = c1 == c1
+       _ = c1 /* ERROR mismatched types */ == c1r
+       _ = c1 /* ERROR mismatched types */ == c1s
+       _ = c1r /* ERROR mismatched types */ == c1s
+       _ = c1 == c1a
+       _ = c1a == c1
+       _ = c1 /* ERROR mismatched types */ == c2
+       _ = c1a /* ERROR mismatched types */ == c2
+
+       // various element types (unnamed types)
+       var (
+               d1 chan int
+               d1r <-chan int
+               d1s chan<- int
+               d1a chan<- int
+               d2 chan float32
+       )
+       _ = d1 == d1
+       _ = d1 == d1r
+       _ = d1 == d1s
+       _ = d1r /* ERROR mismatched types */ == d1s
+       _ = d1 == d1a
+       _ = d1a == d1
+       _ = d1 /* ERROR mismatched types */ == d2
+       _ = d1a /* ERROR mismatched types */ == d2
+}
+
+// for interfaces test
+type S1 struct{}
+type S11 struct{}
+type S2 struct{}
+func (*S1) m() int
+func (*S11) m() int
+func (*S11) n()
+func (*S2) m() float32
+
+func interfaces() {
+       // basics
+       var i, j interface{ m() int }
+       _ = i == j
+       _ = i != j
+       _ = i == nil
+       _ = i /* ERROR < not defined */ < j
+
+       // various interfaces
+       var ii interface { m() int; n() }
+       var k interface { m() float32 }
+       _ = i == ii
+       _ = i /* ERROR mismatched types */ == k
+
+       // interfaces vs values
+       var s1 S1
+       var s11 S11
+       var s2 S2
+
+       _ = i == 0 /* ERROR cannot convert */
+       _ = i /* ERROR mismatched types */ == s1
+       _ = i == &s1
+       _ = i == &s11
+
+       _ = i /* ERROR mismatched types */ == s2
+       _ = i /* ERROR mismatched types */ == &s2
+
+       // issue #28164
+       // testcase from issue
+       _ = interface /* ERROR cannot compare */ {}(nil) == []int(nil)
+
+       // related cases
+       var e interface{}
+       var s []int
+       var x int
+       _ = e /* ERROR cannot compare */ == s
+       _ = s /* ERROR cannot compare */ == e
+       _ = e /* ERROR cannot compare */ < x
+       _ = x /* ERROR cannot compare */ < e
+}
+
+func slices() {
+       // basics
+       var s []int
+       _ = s == nil
+       _ = s != nil
+       _ = s /* ERROR < not defined */ < nil
+
+       // slices are not otherwise comparable
+       _ = s /* ERROR == not defined */ == s
+       _ = s /* ERROR < not defined */ < s
+}
+
+func maps() {
+       // basics
+       var m map[string]int
+       _ = m == nil
+       _ = m != nil
+       _ = m /* ERROR < not defined */ < nil
+
+       // maps are not otherwise comparable
+       _ = m /* ERROR == not defined */ == m
+       _ = m /* ERROR < not defined */ < m
+}
+
+func funcs() {
+       // basics
+       var f func(int) float32
+       _ = f == nil
+       _ = f != nil
+       _ = f /* ERROR < not defined */ < nil
+
+       // funcs are not otherwise comparable
+       _ = f /* ERROR == not defined */ == f
+       _ = f /* ERROR < not defined */ < f
+}
diff --git a/src/cmd/compile/internal/types2/testdata/expr3.src b/src/cmd/compile/internal/types2/testdata/expr3.src
new file mode 100644 (file)
index 0000000..071c9bb
--- /dev/null
@@ -0,0 +1,568 @@
+// Copyright 2012 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 expr3
+
+import "time"
+
+func indexes() {
+       var x int
+       _ = 1 /* ERROR "cannot index" */ [0]
+       _ = x /* ERROR "cannot index" */ [0]
+       _ = ( /* ERROR "cannot slice" */ 12 + 3)[1:2]
+
+       var a [10]int
+       _ = a[true /* ERROR "cannot convert" */ ]
+       _ = a["foo" /* ERROR "cannot convert" */ ]
+       _ = a[1.1 /* ERROR "truncated" */ ]
+       _ = a[1.0]
+       _ = a[- /* ERROR "negative" */ 1]
+       _ = a[- /* ERROR "negative" */ 1 :]
+       _ = a[: - /* ERROR "negative" */ 1]
+       _ = a[: /* ERROR "middle index required" */ : /* ERROR "final index required" */ ]
+       _ = a[0: /* ERROR "middle index required" */ : /* ERROR "final index required" */ ]
+       _ = a[0: /* ERROR "middle index required" */ :10]
+       _ = a[:10:10]
+
+       var a0 int
+       a0 = a[0]
+       _ = a0
+       var a1 int32
+       a1 = a /* ERROR "cannot use .* in assignment" */ [1]
+       _ = a1
+
+       _ = a[9]
+       _ = a[10 /* ERROR "index .* out of bounds" */ ]
+       _ = a[1 /* ERROR "overflows" */ <<100]
+       _ = a[10:]
+       _ = a[:10]
+       _ = a[10:10]
+       _ = a[11 /* ERROR "index .* out of bounds" */ :]
+       _ = a[: 11 /* ERROR "index .* out of bounds" */ ]
+       _ = a[: 1 /* ERROR "overflows" */ <<100]
+       _ = a[:10:10]
+       _ = a[:11 /* ERROR "index .* out of bounds" */ :10]
+       _ = a[:10:11 /* ERROR "index .* out of bounds" */ ]
+       _ = a[10:0:10] /* ERROR "invalid slice indices" */
+       _ = a[0:10:0] /* ERROR "invalid slice indices" */
+       _ = a[10:0:0] /* ERROR "invalid slice indices" */
+       _ = &a /* ERROR "cannot take address" */ [:10]
+
+       pa := &a
+       _ = pa[9]
+       _ = pa[10 /* ERROR "index .* out of bounds" */ ]
+       _ = pa[1 /* ERROR "overflows" */ <<100]
+       _ = pa[10:]
+       _ = pa[:10]
+       _ = pa[10:10]
+       _ = pa[11 /* ERROR "index .* out of bounds" */ :]
+       _ = pa[: 11 /* ERROR "index .* out of bounds" */ ]
+       _ = pa[: 1 /* ERROR "overflows" */ <<100]
+       _ = pa[:10:10]
+       _ = pa[:11 /* ERROR "index .* out of bounds" */ :10]
+       _ = pa[:10:11 /* ERROR "index .* out of bounds" */ ]
+       _ = pa[10:0:10] /* ERROR "invalid slice indices" */
+       _ = pa[0:10:0] /* ERROR "invalid slice indices" */
+       _ = pa[10:0:0] /* ERROR "invalid slice indices" */
+       _ = &pa /* ERROR "cannot take address" */ [:10]
+
+       var b [0]int
+       _ = b[0 /* ERROR "index .* out of bounds" */ ]
+       _ = b[:]
+       _ = b[0:]
+       _ = b[:0]
+       _ = b[0:0]
+       _ = b[0:0:0]
+       _ = b[1 /* ERROR "index .* out of bounds" */ :0:0]
+
+       var s []int
+       _ = s[- /* ERROR "negative" */ 1]
+       _ = s[- /* ERROR "negative" */ 1 :]
+       _ = s[: - /* ERROR "negative" */ 1]
+       _ = s[0]
+       _ = s[1:2]
+       _ = s[2:1] /* ERROR "invalid slice indices" */
+       _ = s[2:]
+       _ = s[: 1 /* ERROR "overflows" */ <<100]
+       _ = s[1 /* ERROR "overflows" */ <<100 :]
+       _ = s[1 /* ERROR "overflows" */ <<100 : 1 /* ERROR "overflows" */ <<100]
+       _ = s[: /* ERROR "middle index required" */ :  /* ERROR "final index required" */ ]
+       _ = s[:10:10]
+       _ = s[10:0:10] /* ERROR "invalid slice indices" */
+       _ = s[0:10:0] /* ERROR "invalid slice indices" */
+       _ = s[10:0:0] /* ERROR "invalid slice indices" */
+       _ = &s /* ERROR "cannot take address" */ [:10]
+
+       var m map[string]int
+       _ = m[0 /* ERROR "cannot convert" */ ]
+       _ = m /* ERROR "cannot slice" */ ["foo" : "bar"]
+       _ = m["foo"]
+       // ok is of type bool
+       type mybool bool
+       var ok mybool
+       _, ok = m["bar"]
+       _ = ok
+       _ = m[0 /* ERROR "cannot convert 0" */ ] + "foo" // ERROR "cannot convert"
+
+       var t string
+       _ = t[- /* ERROR "negative" */ 1]
+       _ = t[- /* ERROR "negative" */ 1 :]
+       _ = t[: - /* ERROR "negative" */ 1]
+       _ = t /* ERROR "3-index slice of string" */ [1:2:3]
+       _ = "foo" /* ERROR "3-index slice of string" */ [1:2:3]
+       var t0 byte
+       t0 = t[0]
+       _ = t0
+       var t1 rune
+       t1 = t /* ERROR "cannot use .* in assignment" */ [2]
+       _ = t1
+       _ = ("foo" + "bar")[5]
+       _ = ("foo" + "bar")[6 /* ERROR "index .* out of bounds" */ ]
+
+       const c = "foo"
+       _ = c[- /* ERROR "negative" */ 1]
+       _ = c[- /* ERROR "negative" */ 1 :]
+       _ = c[: - /* ERROR "negative" */ 1]
+       var c0 byte
+       c0 = c[0]
+       _ = c0
+       var c2 float32
+       c2 = c /* ERROR "cannot use .* in assignment" */ [2]
+       _ = c[3 /* ERROR "index .* out of bounds" */ ]
+       _ = ""[0 /* ERROR "index .* out of bounds" */ ]
+       _ = c2
+
+       _ = s[1<<30] // no compile-time error here
+
+       // issue 4913
+       type mystring string
+       var ss string
+       var ms mystring
+       var i, j int
+       ss = "foo"[1:2]
+       ss = "foo"[i:j]
+       ms = "foo" /* ERROR "cannot use .* in assignment" */ [1:2]
+       ms = "foo" /* ERROR "cannot use .* in assignment" */ [i:j]
+       _, _ = ss, ms
+
+       // With type parameters, index expressions may have multiple indices.
+       _ = a[i, j /* ERROR "more than one index" */ ]
+       _ = a[i, j /* ERROR "more than one index" */ , j]
+}
+
+type T struct {
+       x int
+       y func()
+}
+
+func (*T) m() {}
+
+func method_expressions() {
+       _ = T.a /* ERROR "no field or method" */
+       _ = T.x /* ERROR "has no method" */
+       _ = T.m /* ERROR "cannot call pointer method m on T" */
+       _ = (*T).m
+
+       var f func(*T) = T.m /* ERROR "cannot call pointer method m on T" */
+       var g func(*T) = (*T).m
+       _, _ = f, g
+
+       _ = T.y /* ERROR "has no method" */
+       _ = (*T).y /* ERROR "has no method" */
+}
+
+func struct_literals() {
+       type T0 struct {
+               a, b, c int
+       }
+
+       type T1 struct {
+               T0
+               a, b int
+               u float64
+               s string
+       }
+
+       // keyed elements
+       _ = T1{}
+       _ = T1{a: 0, 1 /* ERROR "mixture of .* elements" */ }
+       _ = T1{aa /* ERROR "unknown field" */ : 0}
+       _ = T1{1 /* ERROR "invalid field name" */ : 0}
+       _ = T1{a: 0, s: "foo", u: 0, a /* ERROR "duplicate field" */: 10}
+       _ = T1{a: "foo" /* ERROR "cannot convert" */ }
+       _ = T1{c /* ERROR "unknown field" */ : 0}
+       _ = T1{T0: { /* ERROR "missing type" */ }} // struct literal element type may not be elided
+       _ = T1{T0: T0{}}
+       _ = T1{T0 /* ERROR "invalid field name" */ .a: 0}
+
+       // unkeyed elements
+       _ = T0{1, 2, 3}
+       _ = T0{1, b /* ERROR "mixture" */ : 2, 3}
+       _ = T0{1, 2} /* ERROR "too few values" */
+       _ = T0{1, 2, 3, 4  /* ERROR "too many values" */ }
+       _ = T0{1, "foo" /* ERROR "cannot convert" */, 3.4  /* ERROR "truncated" */}
+
+       // invalid type
+       type P *struct{
+               x int
+       }
+       _ = P /* ERROR "invalid composite literal type" */ {}
+
+       // unexported fields
+       _ = time.Time{}
+       _ = time.Time{sec /* ERROR "unknown field" */ : 0}
+       _ = time.Time{
+               0 /* ERROR implicit assignment to unexported field wall in time.Time literal */,
+               0 /* ERROR implicit assignment */ ,
+               nil /* ERROR implicit assignment */ ,
+       }
+}
+
+func array_literals() {
+       type A0 [0]int
+       _ = A0{}
+       _ = A0{0 /* ERROR "index .* out of bounds" */}
+       _ = A0{0 /* ERROR "index .* out of bounds" */ : 0}
+
+       type A1 [10]int
+       _ = A1{}
+       _ = A1{0, 1, 2}
+       _ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+       _ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /* ERROR "index .* out of bounds" */ }
+       _ = A1{- /* ERROR "negative" */ 1: 0}
+       _ = A1{8: 8, 9}
+       _ = A1{8: 8, 9, 10 /* ERROR "index .* out of bounds" */ }
+       _ = A1{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+       _ = A1{5: 5, 6, 7, 3: 3, 4}
+       _ = A1{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
+       _ = A1{10 /* ERROR "index .* out of bounds" */ : 10, 10 /* ERROR "index .* out of bounds" */ : 10}
+       _ = A1{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
+       _ = A1{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
+       _ = A1{2.0}
+       _ = A1{2.1 /* ERROR "truncated" */ }
+       _ = A1{"foo" /* ERROR "cannot convert" */ }
+
+       // indices must be integer constants
+       i := 1
+       const f = 2.1
+       const s = "foo"
+       _ = A1{i /* ERROR "index i must be integer constant" */ : 0}
+       _ = A1{f /* ERROR "truncated" */ : 0}
+       _ = A1{s /* ERROR "cannot convert" */ : 0}
+
+       a0 := [...]int{}
+       assert(len(a0) == 0)
+
+       a1 := [...]int{0, 1, 2}
+       assert(len(a1) == 3)
+       var a13 [3]int
+       var a14 [4]int
+       a13 = a1
+       a14 = a1 /* ERROR "cannot use .* in assignment" */
+       _, _ = a13, a14
+
+       a2 := [...]int{- /* ERROR "negative" */ 1: 0}
+       _ = a2
+
+       a3 := [...]int{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+       assert(len(a3) == 5) // somewhat arbitrary
+
+       a4 := [...]complex128{0, 1, 2, 1<<10-2: -1i, 1i, 400: 10, 12, 14}
+       assert(len(a4) == 1024)
+
+       // composite literal element types may be elided
+       type T []int
+       _ = [10]T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+       a6 := [...]T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+       assert(len(a6) == 8)
+
+       // recursively so
+       _ = [10][10]T{{}, [10]T{{}}, {{1, 2, 3}}}
+
+       // from the spec
+       type Point struct { x, y float32 }
+       _ = [...]Point{Point{1.5, -3.5}, Point{0, 0}}
+       _ = [...]Point{{1.5, -3.5}, {0, 0}}
+       _ = [][]int{[]int{1, 2, 3}, []int{4, 5}}
+       _ = [][]int{{1, 2, 3}, {4, 5}}
+       _ = [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
+       _ = [...]*Point{{1.5, -3.5}, {0, 0}}
+}
+
+func slice_literals() {
+       type S0 []int
+       _ = S0{}
+       _ = S0{0, 1, 2}
+       _ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+       _ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+       _ = S0{- /* ERROR "negative" */ 1: 0}
+       _ = S0{8: 8, 9}
+       _ = S0{8: 8, 9, 10}
+       _ = S0{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+       _ = S0{5: 5, 6, 7, 3: 3, 4}
+       _ = S0{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
+       _ = S0{10: 10, 10 /* ERROR "duplicate index" */ : 10}
+       _ = S0{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
+       _ = S0{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
+       _ = S0{2.0}
+       _ = S0{2.1 /* ERROR "truncated" */ }
+       _ = S0{"foo" /* ERROR "cannot convert" */ }
+
+       // indices must be resolved correctly
+       const index1 = 1
+       _ = S0{index1: 1}
+       _ = S0{index2: 2}
+       _ = S0{index3 /* ERROR "undeclared name" */ : 3}
+
+       // indices must be integer constants
+       i := 1
+       const f = 2.1
+       const s = "foo"
+       _ = S0{i /* ERROR "index i must be integer constant" */ : 0}
+       _ = S0{f /* ERROR "truncated" */ : 0}
+       _ = S0{s /* ERROR "cannot convert" */ : 0}
+
+       // composite literal element types may be elided
+       type T []int
+       _ = []T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+       _ = [][]int{{1, 2, 3}, {4, 5}}
+
+       // recursively so
+       _ = [][]T{{}, []T{{}}, {{1, 2, 3}}}
+
+       // issue 17954
+       type T0 *struct { s string }
+       _ = []T0{{}}
+       _ = []T0{{"foo"}}
+
+       type T1 *struct{ int }
+       _ = []T1{}
+       _ = []T1{{0}, {1}, {2}}
+
+       type T2 T1
+       _ = []T2{}
+       _ = []T2{{0}, {1}, {2}}
+
+       _ = map[T0]T2{}
+       _ = map[T0]T2{{}: {}}
+}
+
+const index2 int = 2
+
+type N int
+func (N) f() {}
+
+func map_literals() {
+       type M0 map[string]int
+       type M1 map[bool]int
+       type M2 map[*int]int
+
+       _ = M0{}
+       _ = M0{1 /* ERROR "missing key" */ }
+       _ = M0{1 /* ERROR "cannot convert" */ : 2}
+       _ = M0{"foo": "bar" /* ERROR "cannot convert" */ }
+       _ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
+
+       _ = map[interface{}]int{2: 1, 2 /* ERROR "duplicate key" */ : 1}
+       _ = map[interface{}]int{int(2): 1, int16(2): 1}
+       _ = map[interface{}]int{int16(2): 1, int16 /* ERROR "duplicate key" */ (2): 1}
+
+       type S string
+
+       _ = map[interface{}]int{"a": 1, "a" /* ERROR "duplicate key" */ : 1}
+       _ = map[interface{}]int{"a": 1, S("a"): 1}
+       _ = map[interface{}]int{S("a"): 1, S /* ERROR "duplicate key" */ ("a"): 1}
+       _ = map[interface{}]int{1.0: 1, 1.0 /* ERROR "duplicate key" */: 1}
+       _ = map[interface{}]int{int64(-1): 1, int64 /* ERROR "duplicate key" */ (-1) : 1}
+       _ = map[interface{}]int{^uint64(0): 1, ^ /* ERROR "duplicate key" */ uint64(0): 1}
+       _ = map[interface{}]int{complex(1,2): 1, complex /* ERROR "duplicate key" */ (1,2) : 1}
+
+       type I interface {
+               f()
+       }
+
+       _ = map[I]int{N(0): 1, N(2): 1}
+       _ = map[I]int{N(2): 1, N /* ERROR "duplicate key" */ (2): 1}
+
+       // map keys must be resolved correctly
+       key1 := "foo"
+       _ = M0{key1: 1}
+       _ = M0{key2: 2}
+       _ = M0{key3 /* ERROR "undeclared name" */ : 2}
+
+       var value int
+       _ = M1{true: 1, false: 0}
+       _ = M2{nil: 0, &value: 1}
+
+       // composite literal element types may be elided
+       type T [2]int
+       _ = map[int]T{0: T{3, 4}, 1: {5, 6}}
+
+       // recursively so
+       _ = map[int][]T{0: {}, 1: {{}, T{1, 2}}}
+
+       // composite literal key types may be elided
+       _ = map[T]int{T{3, 4}: 0, {5, 6}: 1}
+
+       // recursively so
+       _ = map[[2]T]int{{}: 0, {{}}: 1, [2]T{{}}: 2, {T{1, 2}}: 3}
+
+       // composite literal element and key types may be elided
+       _ = map[T]T{{}: {}, {1, 2}: T{3, 4}, T{4, 5}: {}}
+       _ = map[T]M0{{} : {}, T{1, 2}: M0{"foo": 0}, {1, 3}: {"foo": 1}}
+
+       // recursively so
+       _ = map[[2]T][]T{{}: {}, {{}}: {{}, T{1, 2}}, [2]T{{}}: nil, {T{1, 2}}: {{}, {}}}
+
+       // from the spec
+       type Point struct { x, y float32 }
+       _ = map[string]Point{"orig": {0, 0}}
+       _ = map[*Point]string{{0, 0}: "orig"}
+
+       // issue 17954
+       type T0 *struct{ s string }
+       type T1 *struct{ int }
+       type T2 T1
+
+       _ = map[T0]T2{}
+       _ = map[T0]T2{{}: {}}
+}
+
+var key2 string = "bar"
+
+type I interface {
+       m()
+}
+
+type I2 interface {
+       m(int)
+}
+
+type T1 struct{}
+type T2 struct{}
+
+func (T2) m(int) {}
+
+type mybool bool
+
+func type_asserts() {
+       var x int
+       _ = x /* ERROR "not an interface" */ .(int)
+
+       var e interface{}
+       var ok bool
+       x, ok = e.(int)
+       _ = ok
+
+       // ok value is of type bool
+       var myok mybool
+       _, myok = e.(int)
+       _ = myok
+
+       var t I
+       _ = t /* ERROR "use of .* outside type switch" */ .(type)
+       _ = t /* ERROR "missing method m" */ .(T)
+       _ = t.(*T)
+       _ = t /* ERROR "missing method m" */ .(T1)
+       _ = t /* ERROR "wrong type for method m" */ .(T2)
+       _ = t /* STRICT "wrong type for method m" */ .(I2) // only an error in strict mode (issue 8561)
+
+       // e doesn't statically have an m, but may have one dynamically.
+       _ = e.(I2)
+}
+
+func f0() {}
+func f1(x int) {}
+func f2(u float32, s string) {}
+func fs(s []byte) {}
+func fv(x ...int) {}
+func fi(x ... interface{}) {}
+func (T) fm(x ...int)
+
+func g0() {}
+func g1() int { return 0}
+func g2() (u float32, s string) { return }
+func gs() []byte { return nil }
+
+func _calls() {
+       var x int
+       var y float32
+       var s []int
+
+       f0()
+       _ = f0 /* ERROR "used as value" */ ()
+       f0(g0 /* ERROR "too many arguments" */ )
+
+       f1(0)
+       f1(x)
+       f1(10.0)
+       f1() /* ERROR "not enough arguments" */
+       f1(x, y /* ERROR "too many arguments" */ )
+       f1(s /* ERROR "cannot use .* in argument" */ )
+       f1(x ... /* ERROR "cannot use ..." */ )
+       f1(g0 /* ERROR "used as value" */ ())
+       f1(g1())
+       f1(g2 /* ERROR "too many arguments" */ ())
+
+       f2() /* ERROR "not enough arguments" */
+       f2(3.14) /* ERROR "not enough arguments" */
+       f2(3.14, "foo")
+       f2(x /* ERROR "cannot use .* in argument" */ , "foo")
+       f2(g0 /* ERROR "used as value" */ ())
+       f2(g1()) /* ERROR "not enough arguments" */
+       f2(g2())
+
+       fs() /* ERROR "not enough arguments" */
+       fs(g0 /* ERROR "used as value" */ ())
+       fs(g1 /* ERROR "cannot use .* in argument" */ ())
+       fs(g2 /* ERROR "too many arguments" */ ())
+       fs(gs())
+
+       fv()
+       fv(1, 2.0, x)
+       fv(s /* ERROR "cannot use .* in argument" */ )
+       fv(s...)
+       fv(x /* ERROR "cannot use" */ ...)
+       fv(1, s /* ERROR "too many arguments" */ ... )
+       fv(gs /* ERROR "cannot use .* in argument" */ ())
+       fv(gs /* ERROR "cannot use .* in argument" */ ()...)
+
+       var t T
+       t.fm()
+       t.fm(1, 2.0, x)
+       t.fm(s /* ERROR "cannot use .* in argument" */ )
+       t.fm(g1())
+       t.fm(1, s /* ERROR "too many arguments" */ ... )
+       t.fm(gs /* ERROR "cannot use .* in argument" */ ())
+       t.fm(gs /* ERROR "cannot use .* in argument" */ ()...)
+
+       T.fm(t, )
+       T.fm(t, 1, 2.0, x)
+       T.fm(t, s /* ERROR "cannot use .* in argument" */ )
+       T.fm(t, g1())
+       T.fm(t, 1, s /* ERROR "too many arguments" */ ... )
+       T.fm(t, gs /* ERROR "cannot use .* in argument" */ ())
+       T.fm(t, gs /* ERROR "cannot use .* in argument" */ ()...)
+
+       var i interface{ fm(x ...int) } = t
+       i.fm()
+       i.fm(1, 2.0, x)
+       i.fm(s /* ERROR "cannot use .* in argument" */ )
+       i.fm(g1())
+       i.fm(1, s /* ERROR "too many arguments" */ ... )
+       i.fm(gs /* ERROR "cannot use .* in argument" */ ())
+       i.fm(gs /* ERROR "cannot use .* in argument" */ ()...)
+
+       fi()
+       fi(1, 2.0, x, 3.14, "foo")
+       fi(g2())
+       fi(0, g2)
+       fi(0, g2 /* ERROR "2-valued g2" */ ())
+}
+
+func issue6344() {
+       type T []interface{}
+       var x T
+       fi(x...) // ... applies also to named slices
+}
diff --git a/src/cmd/compile/internal/types2/testdata/gotos.src b/src/cmd/compile/internal/types2/testdata/gotos.src
new file mode 100644 (file)
index 0000000..069a94b
--- /dev/null
@@ -0,0 +1,560 @@
+// Copyright 2011 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.
+
+// This file is a modified copy of $GOROOT/test/goto.go.
+
+package gotos
+
+var (
+       i, n int
+       x    []int
+       c    chan int
+       m    map[int]int
+       s    string
+)
+
+// goto after declaration okay
+func _() {
+       x := 1
+       goto L
+L:
+       _ = x
+}
+
+// goto before declaration okay
+func _() {
+       goto L
+L:
+       x := 1
+       _ = x
+}
+
+// goto across declaration not okay
+func _() {
+       goto L /* ERROR "goto L jumps over variable declaration at line 36" */
+       x := 1
+       _ = x
+L:
+}
+
+// goto across declaration in inner scope okay
+func _() {
+       goto L
+       {
+               x := 1
+               _ = x
+       }
+L:
+}
+
+// goto across declaration after inner scope not okay
+func _() {
+       goto L /* ERROR "goto L jumps over variable declaration at line 58" */
+       {
+               x := 1
+               _ = x
+       }
+       x := 1
+       _ = x
+L:
+}
+
+// goto across declaration in reverse okay
+func _() {
+L:
+       x := 1
+       _ = x
+       goto L
+}
+
+func _() {
+L: L1:
+       x := 1
+       _ = x
+       goto L
+       goto L1
+}
+
+// error shows first offending variable
+func _() {
+       goto L /* ERROR "goto L jumps over variable declaration at line 84" */
+       x := 1
+       _ = x
+       y := 1
+       _ = y
+L:
+}
+
+// goto not okay even if code path is dead
+func _() {
+       goto L /* ERROR "goto L jumps over variable declaration" */
+       x := 1
+       _ = x
+       y := 1
+       _ = y
+       return
+L:
+}
+
+// goto into outer block okay
+func _() {
+       {
+               goto L
+       }
+L:
+}
+
+func _() {
+       {
+               goto L
+               goto L1
+       }
+L: L1:
+}
+
+// goto backward into outer block okay
+func _() {
+L:
+       {
+               goto L
+       }
+}
+
+func _() {
+L: L1:
+       {
+               goto L
+               goto L1
+       }
+}
+
+// goto into inner block not okay
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       {
+       L:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       goto L1 /* ERROR "goto L1 jumps into block" */
+       {
+       L: L1:
+       }
+}
+
+// goto backward into inner block still not okay
+func _() {
+       {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       {
+       L: L1:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+       goto L1 /* ERROR "goto L1 jumps into block" */
+}
+
+// error shows first (outermost) offending block
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       {
+               {
+                       {
+                       L:
+                       }
+               }
+       }
+}
+
+// error prefers block diagnostic over declaration diagnostic
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       x := 1
+       _ = x
+       {
+       L:
+       }
+}
+
+// many kinds of blocks, all invalid to jump into or among,
+// but valid to jump out of
+
+// if
+
+func _() {
+L:
+       if true {
+               goto L
+       }
+}
+
+func _() {
+L:
+       if true {
+               goto L
+       } else {
+       }
+}
+
+func _() {
+L:
+       if false {
+       } else {
+               goto L
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       if true {
+       L:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       if true {
+       L:
+       } else {
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       if true {
+       } else {
+       L:
+       }
+}
+
+func _() {
+       if false {
+       L:
+       } else {
+               goto L /* ERROR "goto L jumps into block" */
+       }
+}
+
+func _() {
+       if true {
+               goto L /* ERROR "goto L jumps into block" */
+       } else {
+       L:
+       }
+}
+
+func _() {
+       if true {
+               goto L /* ERROR "goto L jumps into block" */
+       } else if false {
+       L:
+       }
+}
+
+func _() {
+       if true {
+               goto L /* ERROR "goto L jumps into block" */
+       } else if false {
+       L:
+       } else {
+       }
+}
+
+func _() {
+       if true {
+               goto L /* ERROR "goto L jumps into block" */
+       } else if false {
+       } else {
+       L:
+       }
+}
+
+func _() {
+       if true {
+               goto L /* ERROR "goto L jumps into block" */
+       } else {
+               L:
+       }
+}
+
+func _() {
+       if true {
+               L:
+       } else {
+               goto L /* ERROR "goto L jumps into block" */
+       }
+}
+
+// for
+
+func _() {
+       for {
+               goto L
+       }
+L:
+}
+
+func _() {
+       for {
+               goto L
+       L:
+       }
+}
+
+func _() {
+       for {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       for {
+               goto L
+       L1:
+       }
+L:
+       goto L1 /* ERROR "goto L1 jumps into block" */
+}
+
+func _() {
+       for i < n {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       for i = 0; i < n; i++ {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       for i = range x {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       for i = range c {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       for i = range m {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+       for i = range s {
+       L:
+       }
+       goto L /* ERROR "goto L jumps into block" */
+}
+
+// switch
+
+func _() {
+L:
+       switch i {
+       case 0:
+               goto L
+       }
+}
+
+func _() {
+L:
+       switch i {
+       case 0:
+
+       default:
+               goto L
+       }
+}
+
+func _() {
+       switch i {
+       case 0:
+
+       default:
+       L:
+               goto L
+       }
+}
+
+func _() {
+       switch i {
+       case 0:
+
+       default:
+               goto L
+       L:
+       }
+}
+
+func _() {
+       switch i {
+       case 0:
+               goto L
+       L:
+               ;
+       default:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       switch i {
+       case 0:
+       L:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       switch i {
+       case 0:
+       L:
+               ;
+       default:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       switch i {
+       case 0:
+       default:
+       L:
+       }
+}
+
+func _() {
+       switch i {
+       default:
+               goto L /* ERROR "goto L jumps into block" */
+       case 0:
+       L:
+       }
+}
+
+func _() {
+       switch i {
+       case 0:
+       L:
+               ;
+       default:
+               goto L /* ERROR "goto L jumps into block" */
+       }
+}
+
+// select
+// different from switch.  the statement has no implicit block around it.
+
+func _() {
+L:
+       select {
+       case <-c:
+               goto L
+       }
+}
+
+func _() {
+L:
+       select {
+       case c <- 1:
+
+       default:
+               goto L
+       }
+}
+
+func _() {
+       select {
+       case <-c:
+
+       default:
+       L:
+               goto L
+       }
+}
+
+func _() {
+       select {
+       case c <- 1:
+
+       default:
+               goto L
+       L:
+       }
+}
+
+func _() {
+       select {
+       case <-c:
+               goto L
+       L:
+               ;
+       default:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       select {
+       case c <- 1:
+       L:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       select {
+       case c <- 1:
+       L:
+               ;
+       default:
+       }
+}
+
+func _() {
+       goto L /* ERROR "goto L jumps into block" */
+       select {
+       case <-c:
+       default:
+       L:
+       }
+}
+
+func _() {
+       select {
+       default:
+               goto L /* ERROR "goto L jumps into block" */
+       case <-c:
+       L:
+       }
+}
+
+func _() {
+       select {
+       case <-c:
+       L:
+               ;
+       default:
+               goto L /* ERROR "goto L jumps into block" */
+       }
+}
diff --git a/src/cmd/compile/internal/types2/testdata/importC.src b/src/cmd/compile/internal/types2/testdata/importC.src
new file mode 100644 (file)
index 0000000..f55be2d
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2015 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 importC
+
+import "C"
+import _ /* ERROR cannot rename import "C" */ "C"
+import foo /* ERROR cannot rename import "C" */ "C"
+import . /* ERROR cannot rename import "C" */ "C"
+
+// Test cases extracted from issue #22090.
+
+import "unsafe"
+
+const _ C.int = 0xff // no error due to invalid constant type
+
+type T struct {
+       Name    string
+       Ordinal int
+}
+
+func _(args []T) {
+       var s string
+       for i, v := range args {
+               cname := C.CString(v.Name)
+               args[i].Ordinal = int(C.sqlite3_bind_parameter_index(s, cname)) // no error due to i not being "used"
+               C.free(unsafe.Pointer(cname))
+       }
+}
+
+type CType C.Type
+
+const _ CType = C.X // no error due to invalid constant type
+const _ = C.X
+
+// Test cases extracted from issue #23712.
+
+func _() {
+       var a [C.ArrayLength]byte
+       _ = a[0] // no index out of bounds error here
+}
+
+// Additional tests to verify fix for #23712.
+
+func _() {
+       var a [C.ArrayLength1]byte
+       _ = 1 / len(a) // no division by zero error here and below
+       _ = 1 / cap(a)
+       _ = uint(unsafe.Sizeof(a)) // must not be negative
+
+       var b [C.ArrayLength2]byte
+       a = b // should be valid
+}
diff --git a/src/cmd/compile/internal/types2/testdata/importdecl0/importdecl0a.src b/src/cmd/compile/internal/types2/testdata/importdecl0/importdecl0a.src
new file mode 100644 (file)
index 0000000..e96fca3
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2013 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 importdecl0
+
+import ()
+
+import (
+       // we can have multiple blank imports (was bug)
+       _ "math"
+       _ "net/rpc"
+       init /* ERROR "cannot declare init" */ "fmt"
+       // reflect defines a type "flag" which shows up in the gc export data
+       "reflect"
+       . /* ERROR "imported but not used" */ "reflect"
+)
+
+import "math" /* ERROR "imported but not used" */
+import m /* ERROR "imported but not used as m" */ "math"
+import _ "math"
+
+import (
+       "math/big" /* ERROR "imported but not used" */
+       b /* ERROR "imported but not used" */ "math/big"
+       _ "math/big"
+)
+
+import "fmt"
+import f1 "fmt"
+import f2 "fmt"
+
+// reflect.flag must not be visible in this package
+type flag int
+type _ reflect.flag /* ERROR "not exported" */
+
+// imported package name may conflict with local objects
+type reflect /* ERROR "reflect already declared" */ int
+
+// dot-imported exported objects may conflict with local objects
+type Value /* ERROR "Value already declared through dot-import of package reflect" */ struct{}
+
+var _ = fmt.Println // use "fmt"
+
+func _() {
+       f1.Println() // use "fmt"
+}
+
+func _() {
+       _ = func() {
+               f2.Println() // use "fmt"
+       }
+}
diff --git a/src/cmd/compile/internal/types2/testdata/importdecl0/importdecl0b.src b/src/cmd/compile/internal/types2/testdata/importdecl0/importdecl0b.src
new file mode 100644 (file)
index 0000000..48ecb5e
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2013 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 importdecl0
+
+import "math"
+import m "math"
+
+import . "testing" // declares T in file scope
+import . /* ERROR "imported but not used" */ "unsafe"
+import . "fmt"     // declares Println in file scope
+
+import (
+       "" /* ERROR invalid import path */
+       "a!b" /* ERROR invalid import path */
+       "abc\xffdef" /* ERROR invalid import path */
+)
+
+// using "math" in this file doesn't affect its use in other files
+const Pi0 = math.Pi
+const Pi1 = m.Pi
+
+type _ T // use "testing"
+
+func _() func() interface{} {
+       return func() interface{} {
+               return Println // use "fmt"
+       }
+}
diff --git a/src/cmd/compile/internal/types2/testdata/importdecl1/importdecl1a.src b/src/cmd/compile/internal/types2/testdata/importdecl1/importdecl1a.src
new file mode 100644 (file)
index 0000000..d377c01
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2014 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.
+
+// Test case for issue 8969.
+
+package importdecl1
+
+import "go/ast"
+import . "unsafe"
+
+var _ Pointer // use dot-imported package unsafe
+
+// Test cases for issue 23914.
+
+type A interface {
+       // Methods m1, m2 must be type-checked in this file scope
+       // even when embedded in an interface in a different
+       // file of the same package.
+       m1() ast.Node
+       m2() Pointer
+}
diff --git a/src/cmd/compile/internal/types2/testdata/importdecl1/importdecl1b.src b/src/cmd/compile/internal/types2/testdata/importdecl1/importdecl1b.src
new file mode 100644 (file)
index 0000000..ee70bbd
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2014 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 importdecl1
+
+import . /* ERROR "imported but not used" */ "unsafe"
+
+type B interface {
+       A
+}
diff --git a/src/cmd/compile/internal/types2/testdata/init0.src b/src/cmd/compile/internal/types2/testdata/init0.src
new file mode 100644 (file)
index 0000000..6e8746a
--- /dev/null
@@ -0,0 +1,106 @@
+// Copyright 2013 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.
+
+// initialization cycles
+
+package init0
+
+// initialization cycles (we don't know the types)
+const (
+       s0 /* ERROR initialization cycle */ = s0
+
+       x0 /* ERROR initialization cycle */ = y0
+       y0 = x0
+
+       a0 = b0
+       b0 /* ERROR initialization cycle */ = c0
+       c0 = d0
+       d0 = b0
+)
+
+var (
+       s1 /* ERROR initialization cycle */ = s1
+
+       x1 /* ERROR initialization cycle */ = y1
+       y1 = x1
+
+       a1 = b1
+       b1 /* ERROR initialization cycle */ = c1
+       c1 = d1
+       d1 = b1
+)
+
+// initialization cycles (we know the types)
+const (
+       s2 /* ERROR initialization cycle */ int = s2
+
+       x2 /* ERROR initialization cycle */ int = y2
+       y2 = x2
+
+       a2 = b2
+       b2 /* ERROR initialization cycle */ int = c2
+       c2 = d2
+       d2 = b2
+)
+
+var (
+       s3 /* ERROR initialization cycle */ int = s3
+
+       x3 /* ERROR initialization cycle */ int = y3
+       y3 = x3
+
+       a3 = b3
+       b3 /* ERROR initialization cycle */ int = c3
+       c3 = d3
+       d3 = b3
+)
+
+// cycles via struct fields
+
+type S1 struct {
+       f int
+}
+const cx3 S1 /* ERROR invalid constant type */ = S1{cx3.f}
+var vx3 /* ERROR initialization cycle */ S1 = S1{vx3.f}
+
+// cycles via functions
+
+var x4 = x5
+var x5 /* ERROR initialization cycle */ = f1()
+func f1() int { return x5*10 }
+
+var x6, x7 /* ERROR initialization cycle */ = f2()
+var x8 = x7
+func f2() (int, int) { return f3() + f3(), 0 }
+func f3() int { return x8 }
+
+// cycles via function literals
+
+var x9 /* ERROR initialization cycle */ = func() int { return x9 }()
+
+var x10 /* ERROR initialization cycle */ = f4()
+
+func f4() int {
+       _ = func() {
+               _ = x10
+       }
+       return 0
+}
+
+// cycles via method expressions
+
+type T1 struct{}
+
+func (T1) m() bool { _ = x11; return false }
+
+var x11 /* ERROR initialization cycle */ = T1.m(T1{})
+
+// cycles via method values
+
+type T2 struct{}
+
+func (T2) m() bool { _ = x12; return false }
+
+var t1 T2
+var x12 /* ERROR initialization cycle */ = t1.m
diff --git a/src/cmd/compile/internal/types2/testdata/init1.src b/src/cmd/compile/internal/types2/testdata/init1.src
new file mode 100644 (file)
index 0000000..39ca314
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright 2013 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.
+
+// initialization cycles
+
+package init1
+
+// issue 6683 (marked as WorkingAsIntended)
+
+type T0 struct{}
+
+func (T0) m() int { return y0 }
+
+var x0 = T0{}
+
+var y0 /* ERROR initialization cycle */ = x0.m()
+
+type T1 struct{}
+
+func (T1) m() int { return y1 }
+
+var x1 interface {
+       m() int
+} = T1{}
+
+var y1 = x1.m() // no cycle reported, x1 is of interface type
+
+// issue 6703 (modified)
+
+var x2 /* ERROR initialization cycle */ = T2.m
+
+var y2 = x2
+
+type T2 struct{}
+
+func (T2) m() int {
+       _ = y2
+       return 0
+}
+
+var x3 /* ERROR initialization cycle */ = T3.m(T3{}) // <<<< added (T3{})
+
+var y3 = x3
+
+type T3 struct{}
+
+func (T3) m() int {
+       _ = y3
+       return 0
+}
+
+var x4 /* ERROR initialization cycle */ = T4{}.m // <<<< added {}
+
+var y4 = x4
+
+type T4 struct{}
+
+func (T4) m() int {
+       _ = y4
+       return 0
+}
+
+var x5 /* ERROR initialization cycle */ = T5{}.m() // <<<< added ()
+
+var y5 = x5
+
+type T5 struct{}
+
+func (T5) m() int {
+       _ = y5
+       return 0
+}
+
+// issue 4847
+// simplified test case
+
+var x6 = f6
+var y6 /* ERROR initialization cycle */ = f6
+func f6() { _ = y6 }
+
+// full test case
+
+type (
+      E int
+      S int
+)
+
+type matcher func(s *S) E
+
+func matchList(s *S) E { return matcher(matchAnyFn)(s) }
+
+var foo = matcher(matchList)
+
+var matchAny /* ERROR initialization cycle */ = matcher(matchList)
+
+func matchAnyFn(s *S) (err E) { return matchAny(s) }
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/testdata/init2.src b/src/cmd/compile/internal/types2/testdata/init2.src
new file mode 100644 (file)
index 0000000..614db6c
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright 2014 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.
+
+// initialization cycles
+
+package init2
+
+// cycles through functions
+
+func f1() int { _ = x1; return 0 }
+var x1 /* ERROR initialization cycle */ = f1
+
+func f2() int { _ = x2; return 0 }
+var x2 /* ERROR initialization cycle */ = f2()
+
+// cycles through method expressions
+
+type T3 int
+func (T3) m() int { _ = x3; return 0 }
+var x3 /* ERROR initialization cycle */ = T3.m
+
+type T4 int
+func (T4) m() int { _ = x4; return 0 }
+var x4 /* ERROR initialization cycle */ = T4.m(0)
+
+type T3p int
+func (*T3p) m() int { _ = x3p; return 0 }
+var x3p /* ERROR initialization cycle */ = (*T3p).m
+
+type T4p int
+func (*T4p) m() int { _ = x4p; return 0 }
+var x4p /* ERROR initialization cycle */ = (*T4p).m(nil)
+
+// cycles through method expressions of embedded methods
+
+type T5 struct { E5 }
+type E5 int
+func (E5) m() int { _ = x5; return 0 }
+var x5 /* ERROR initialization cycle */ = T5.m
+
+type T6 struct { E6 }
+type E6 int
+func (E6) m() int { _ = x6; return 0 }
+var x6 /* ERROR initialization cycle */ = T6.m(T6{0})
+
+type T5p struct { E5p }
+type E5p int
+func (*E5p) m() int { _ = x5p; return 0 }
+var x5p /* ERROR initialization cycle */ = (*T5p).m
+
+type T6p struct { E6p }
+type E6p int
+func (*E6p) m() int { _ = x6p; return 0 }
+var x6p /* ERROR initialization cycle */ = (*T6p).m(nil)
+
+// cycles through method values
+
+type T7 int
+func (T7) m() int { _ = x7; return 0 }
+var x7 /* ERROR initialization cycle */ = T7(0).m
+
+type T8 int
+func (T8) m() int { _ = x8; return 0 }
+var x8 /* ERROR initialization cycle */ = T8(0).m()
+
+type T7p int
+func (*T7p) m() int { _ = x7p; return 0 }
+var x7p /* ERROR initialization cycle */ = new(T7p).m
+
+type T8p int
+func (*T8p) m() int { _ = x8p; return 0 }
+var x8p /* ERROR initialization cycle */ = new(T8p).m()
+
+type T7v int
+func (T7v) m() int { _ = x7v; return 0 }
+var x7var T7v
+var x7v /* ERROR initialization cycle */ = x7var.m
+
+type T8v int
+func (T8v) m() int { _ = x8v; return 0 }
+var x8var T8v
+var x8v /* ERROR initialization cycle */ = x8var.m()
+
+type T7pv int
+func (*T7pv) m() int { _ = x7pv; return 0 }
+var x7pvar *T7pv
+var x7pv /* ERROR initialization cycle */ = x7pvar.m
+
+type T8pv int
+func (*T8pv) m() int { _ = x8pv; return 0 }
+var x8pvar *T8pv
+var x8pv /* ERROR initialization cycle */ = x8pvar.m()
+
+// cycles through method values of embedded methods
+
+type T9 struct { E9 }
+type E9 int
+func (E9) m() int { _ = x9; return 0 }
+var x9 /* ERROR initialization cycle */ = T9{0}.m
+
+type T10 struct { E10 }
+type E10 int
+func (E10) m() int { _ = x10; return 0 }
+var x10 /* ERROR initialization cycle */ = T10{0}.m()
+
+type T9p struct { E9p }
+type E9p int
+func (*E9p) m() int { _ = x9p; return 0 }
+var x9p /* ERROR initialization cycle */ = new(T9p).m
+
+type T10p struct { E10p }
+type E10p int
+func (*E10p) m() int { _ = x10p; return 0 }
+var x10p /* ERROR initialization cycle */ = new(T10p).m()
+
+type T9v struct { E9v }
+type E9v int
+func (E9v) m() int { _ = x9v; return 0 }
+var x9var T9v
+var x9v /* ERROR initialization cycle */ = x9var.m
+
+type T10v struct { E10v }
+type E10v int
+func (E10v) m() int { _ = x10v; return 0 }
+var x10var T10v
+var x10v /* ERROR initialization cycle */ = x10var.m()
+
+type T9pv struct { E9pv }
+type E9pv int
+func (*E9pv) m() int { _ = x9pv; return 0 }
+var x9pvar *T9pv
+var x9pv /* ERROR initialization cycle */ = x9pvar.m
+
+type T10pv struct { E10pv }
+type E10pv int
+func (*E10pv) m() int { _ = x10pv; return 0 }
+var x10pvar *T10pv
+var x10pv /* ERROR initialization cycle */ = x10pvar.m()
diff --git a/src/cmd/compile/internal/types2/testdata/issue23203a.src b/src/cmd/compile/internal/types2/testdata/issue23203a.src
new file mode 100644 (file)
index 0000000..48cb588
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2018 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
+
+import "unsafe"
+
+type T struct{}
+
+func (T) m1()                         {}
+func (T) m2([unsafe.Sizeof(T.m1)]int) {}
+
+func main() {}
diff --git a/src/cmd/compile/internal/types2/testdata/issue23203b.src b/src/cmd/compile/internal/types2/testdata/issue23203b.src
new file mode 100644 (file)
index 0000000..638ec6c
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2018 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
+
+import "unsafe"
+
+type T struct{}
+
+func (T) m2([unsafe.Sizeof(T.m1)]int) {}
+func (T) m1()                         {}
+
+func main() {}
diff --git a/src/cmd/compile/internal/types2/testdata/issue25008/issue25008a.src b/src/cmd/compile/internal/types2/testdata/issue25008/issue25008a.src
new file mode 100644 (file)
index 0000000..cf71ca1
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2018 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
+
+import "io"
+
+type A interface {
+        io.Reader
+}
+
+func f(a A) {
+        a.Read(nil)
+}
diff --git a/src/cmd/compile/internal/types2/testdata/issue25008/issue25008b.src b/src/cmd/compile/internal/types2/testdata/issue25008/issue25008b.src
new file mode 100644 (file)
index 0000000..f132b7f
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2018 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 B interface {
+    A
+}
diff --git a/src/cmd/compile/internal/types2/testdata/issue26390.src b/src/cmd/compile/internal/types2/testdata/issue26390.src
new file mode 100644 (file)
index 0000000..b8e67e9
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2018 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 issue26390
+
+type A = T
+
+func (t *T) m() *A { return t }
+
+type T struct{}
diff --git a/src/cmd/compile/internal/types2/testdata/issue28251.src b/src/cmd/compile/internal/types2/testdata/issue28251.src
new file mode 100644 (file)
index 0000000..ef5e61d
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright 2018 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.
+
+// This file contains test cases for various forms of
+// method receiver declarations, per the spec clarification
+// https://golang.org/cl/142757.
+
+package issue28251
+
+// test case from issue28251
+type T struct{}
+
+type T0 = *T
+
+func (T0) m() {}
+
+func _() { (&T{}).m() }
+
+// various alternative forms
+type (
+        T1 = (((T)))
+)
+
+func ((*(T1))) m1() {}
+func _() { (T{}).m2() }
+func _() { (&T{}).m2() }
+
+type (
+        T2 = (((T3)))
+        T3 = T
+)
+
+func (T2) m2() {}
+func _() { (T{}).m2() }
+func _() { (&T{}).m2() }
+
+type (
+        T4 = ((*(T5)))
+        T5 = T
+)
+
+func (T4) m4() {}
+func _() { (T{}).m4 /* ERROR "cannot call pointer method m4 on T" */ () }
+func _() { (&T{}).m4() }
+
+type (
+        T6 = (((T7)))
+        T7 = (*(T8))
+        T8 = T
+)
+
+func (T6) m6() {}
+func _() { (T{}).m6 /* ERROR "cannot call pointer method m6 on T" */ () }
+func _() { (&T{}).m6() }
+
+type (
+        T9 = *T10
+        T10 = *T11
+        T11 = T
+)
+
+func (T9 /* ERROR invalid receiver type \*\*T */ ) m9() {}
+func _() { (T{}).m9 /* ERROR has no field or method m9 */ () }
+func _() { (&T{}).m9 /* ERROR has no field or method m9 */ () }
diff --git a/src/cmd/compile/internal/types2/testdata/issue6977.src b/src/cmd/compile/internal/types2/testdata/issue6977.src
new file mode 100644 (file)
index 0000000..8f4e9ba
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright 2019 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
+
+import "io"
+
+// Alan's initial report.
+
+type I interface { f(); String() string }
+type J interface { g(); String() string }
+
+type IJ1 = interface { I; J }
+type IJ2 = interface { f(); g(); String() string }
+
+var _ = (*IJ1)(nil) == (*IJ2)(nil) // static assert that IJ1 and IJ2 are identical types
+
+// The canonical example.
+
+type ReadWriteCloser interface { io.ReadCloser; io.WriteCloser }
+
+// Some more cases.
+
+type M interface { m() }
+type M32 interface { m() int32 }
+type M64 interface { m() int64 }
+
+type U1 interface { m() }
+type U2 interface { m(); M }
+type U3 interface { M; m() }
+type U4 interface { M; M; M }
+type U5 interface { U1; U2; U3; U4 }
+
+type U6 interface { m(); m /* ERROR duplicate method */ () }
+type U7 interface { M32 /* ERROR duplicate method */ ; m() }
+type U8 interface { m(); M32 /* ERROR duplicate method */ }
+type U9 interface { M32; M64 /* ERROR duplicate method */ }
+
+// Verify that repeated embedding of the same interface(s)
+// eliminates duplicate methods early (rather than at the
+// end) to prevent exponential memory and time use.
+// Without early elimination, computing T29 may take dozens
+// of minutes.
+type (
+        T0 interface { m() }
+        T1 interface { T0; T0 }
+        T2 interface { T1; T1 }
+        T3 interface { T2; T2 }
+        T4 interface { T3; T3 }
+        T5 interface { T4; T4 }
+        T6 interface { T5; T5 }
+        T7 interface { T6; T6 }
+        T8 interface { T7; T7 }
+        T9 interface { T8; T8 }
+
+        T10 interface { T9; T9 }
+        T11 interface { T10; T10 }
+        T12 interface { T11; T11 }
+        T13 interface { T12; T12 }
+        T14 interface { T13; T13 }
+        T15 interface { T14; T14 }
+        T16 interface { T15; T15 }
+        T17 interface { T16; T16 }
+        T18 interface { T17; T17 }
+        T19 interface { T18; T18 }
+
+        T20 interface { T19; T19 }
+        T21 interface { T20; T20 }
+        T22 interface { T21; T21 }
+        T23 interface { T22; T22 }
+        T24 interface { T23; T23 }
+        T25 interface { T24; T24 }
+        T26 interface { T25; T25 }
+        T27 interface { T26; T26 }
+        T28 interface { T27; T27 }
+        T29 interface { T28; T28 }
+)
+
+// Verify that m is present.
+var x T29
+var _ = x.m
diff --git a/src/cmd/compile/internal/types2/testdata/issues.go2 b/src/cmd/compile/internal/types2/testdata/issues.go2
new file mode 100644 (file)
index 0000000..1c73b5d
--- /dev/null
@@ -0,0 +1,249 @@
+// Copyright 2020 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.
+
+// This file contains regression tests for bugs found.
+
+package p
+
+import "io"
+import "context"
+
+// Interfaces are always comparable (though the comparison may panic at runtime).
+func eql[T comparable](x, y T) bool {
+       return x == y
+}
+
+func _() {
+       var x interface{}
+       var y interface{ m() }
+       eql(x, y /* ERROR does not match */ ) // interfaces of different types
+       eql(x, x)
+       eql(y, y)
+       eql(y, nil)
+       eql[io.Reader](nil, nil)
+}
+
+// If we have a receiver of pointer type (below: *T) we must ignore
+// the pointer in the implementation of the method lookup because
+// the type bound of T is an interface and pointer to interface types
+// have no methods and then the lookup would fail.
+type C[T any] interface {
+    m()
+}
+
+// using type bound C
+func _[T C[T]](x *T) {
+       x.m()
+}
+
+// using an interface literal as bound
+func _[T interface{ m() }](x *T) {
+       x.m()
+}
+
+func f2[_ interface{ m1(); m2() }]()
+
+type T struct{}
+func (T) m1()
+func (*T) m2()
+
+func _() {
+       f2[T /* ERROR wrong method signature */ ]()
+       f2[*T]()
+}
+
+// When a type parameter is used as an argument to instantiate a parameterized
+// type with a type list constraint, all of the type argument's types in its
+// bound, but at least one (!), must be in the type list of the bound of the
+// corresponding parameterized type's type parameter.
+type T1[P interface{type uint}] struct{}
+
+func _[P any]() {
+    _ = T1[P /* ERROR P has no type constraints */ ]{}
+}
+
+// This is the original (simplified) program causing the same issue.
+type Unsigned interface {
+       type uint
+}
+
+type T2[U Unsigned] struct {
+    s U
+}
+
+func (u T2[U]) Add1() U {
+    return u.s + 1
+}
+
+func NewT2[U any]() T2[U /* ERROR U has no type constraints */ ] {
+    return T2[U /* ERROR U has no type constraints */ ]{}
+}
+
+func _() {
+    u := NewT2[string]()
+    _ = u.Add1()
+}
+
+// When we encounter an instantiated type such as Elem[T] we must
+// not "expand" the instantiation when the type to be instantiated
+// (Elem in this case) is not yet fully set up.
+type Elem[T any] struct {
+       next *Elem[T]
+       list *List[T]
+}
+
+type List[T any] struct {
+       root Elem[T]
+}
+
+func (l *List[T]) Init() {
+       l.root.next = &l.root
+}
+
+// This is the original program causing the same issue.
+type Element2[TElem any] struct {
+       next, prev *Element2[TElem]
+       list *List2[TElem]
+       Value TElem
+}
+
+type List2[TElem any] struct {
+       root Element2[TElem]
+       len  int
+}
+
+func (l *List2[TElem]) Init() *List2[TElem] {
+       l.root.next = &l.root
+       l.root.prev = &l.root
+       l.len = 0
+       return l
+}
+
+// Self-recursive instantiations must work correctly.
+type A[P any] struct { _ *A[P] }
+
+type AB[P any] struct { _ *BA[P] }
+type BA[P any] struct { _ *AB[P] }
+
+// And a variation that also caused a problem with an
+// unresolved underlying type.
+type Element3[TElem any] struct {
+       next, prev *Element3[TElem]
+       list *List3[TElem]
+       Value TElem
+}
+
+func (e *Element3[TElem]) Next() *Element3[TElem] {
+       if p := e.next; e.list != nil && p != &e.list.root {
+               return p
+       }
+       return nil
+}
+
+type List3[TElem any] struct {
+       root Element3[TElem]
+       len  int
+}
+
+// Infinite generic type declarations must lead to an error.
+type inf1[T any] struct{ _ inf1 /* ERROR illegal cycle */ [T] }
+type inf2[T any] struct{ inf2 /* ERROR illegal cycle */ [T] }
+
+// The implementation of conversions T(x) between integers and floating-point
+// numbers checks that both T and x have either integer or floating-point
+// type. When the type of T or x is a type parameter, the respective simple
+// predicate disjunction in the implementation was wrong because if a type list
+// contains both an integer and a floating-point type, the type parameter is
+// neither an integer or a floating-point number.
+func convert[T1, T2 interface{type int, uint, float32}](v T1) T2 {
+       return T2(v)
+}
+
+func _() {
+       convert[int, uint](5)
+}
+
+// When testing binary operators, for +, the operand types must either be
+// both numeric, or both strings. The implementation had the same problem
+// with this check as the conversion issue above (issue #39623).
+
+func issue39623[T interface{type int, string}](x, y T) T {
+       return x + y
+}
+
+// Simplified, from https://go2goplay.golang.org/p/efS6x6s-9NI:
+func Sum[T interface{type int, string}](s []T) (sum T) {
+       for _, v := range s {
+               sum += v
+       }
+       return
+}
+
+// Assignability of an unnamed pointer type to a type parameter that
+// has a matching underlying type.
+func _[T interface{}, PT interface{type *T}] (x T) PT {
+    return &x
+}
+
+// Indexing of generic types containing type parameters in their type list:
+func at[T interface{ type []E }, E interface{}](x T, i int) E {
+        return x[i]
+}
+
+// A generic type inside a function acts like a named type. Its underlying
+// type is itself, its "operational type" is defined by the type list in
+// the tybe bound, if any.
+func _[T interface{type int}](x T) {
+       type myint int
+       var _ int = int(x)
+       var _ T = 42
+       var _ T = T(myint(42))
+}
+
+// Indexing a generic type with an array type bound checks length.
+// (Example by mdempsky@.)
+func _[T interface { type [10]int }](x T) {
+       _ = x[9] // ok
+       _ = x[20 /* ERROR out of bounds */ ]
+}
+
+// Pointer indirection of a generic type.
+func _[T interface{ type *int }](p T) int {
+       return *p
+}
+
+// Channel sends and receives on generic types.
+func _[T interface{ type chan int }](ch T) int {
+       ch <- 0
+       return <- ch
+}
+
+// Calling of a generic variable.
+func _[T interface{ type func() }](f T) {
+       f()
+       go f()
+}
+
+// We must compare against the underlying type of type list entries
+// when checking if a constraint is satisfied by a type. The under-
+// lying type of each type list entry must be computed after the
+// interface has been instantiated as its typelist may contain a
+// type parameter that was substituted with a defined type.
+// Test case from an (originally) failing example.
+
+type sliceOf[E any] interface{ type []E }
+
+func append[T interface{}, S sliceOf[T], T2 interface{ type T }](s S, t ...T2) S
+
+var f           func()
+var cancelSlice []context.CancelFunc
+var _ = append[context.CancelFunc, []context.CancelFunc, context.CancelFunc](cancelSlice, f)
+
+// A generic function must be instantiated with a type, not a value.
+
+func g[T any](T) T
+
+var _ = g[int]
+var _ = g[nil /* ERROR is not a type */ ]
+var _ = g(0)
diff --git a/src/cmd/compile/internal/types2/testdata/issues.src b/src/cmd/compile/internal/types2/testdata/issues.src
new file mode 100644 (file)
index 0000000..1bfc7fe
--- /dev/null
@@ -0,0 +1,365 @@
+// Copyright 2014 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 issues
+
+import (
+       "fmt"
+       syn "cmd/compile/internal/syntax"
+       t1 "text/template"
+       t2 "html/template"
+)
+
+func issue7035() {
+       type T struct{ X int }
+       _ = func() {
+               fmt.Println() // must refer to imported fmt rather than the fmt below
+       }
+       fmt := new(T)
+       _ = fmt.X
+}
+
+func issue8066() {
+       const (
+               _ = float32(340282356779733661637539395458142568447)
+               _ = float32(340282356779733661637539395458142568448 /* ERROR cannot convert */ )
+       )
+}
+
+// Check that a missing identifier doesn't lead to a spurious error cascade.
+func issue8799a() {
+       x, ok := missing /* ERROR undeclared */ ()
+       _ = !ok
+       _ = x
+}
+
+func issue8799b(x int, ok bool) {
+       x, ok = missing /* ERROR undeclared */ ()
+       _ = !ok
+       _ = x
+}
+
+func issue9182() {
+       type Point C /* ERROR undeclared */ .Point
+       // no error for composite literal based on unknown type
+       _ = Point{x: 1, y: 2}
+}
+
+func f0() (a []int)         { return }
+func f1() (a []int, b int)  { return }
+func f2() (a, b []int)      { return }
+
+func append_([]int, ...int) {}
+
+func issue9473(a []int, b ...int) {
+       // variadic builtin function
+       _ = append(f0())
+       _ = append(f0(), f0()...)
+       _ = append(f1())
+       _ = append(f2 /* ERROR cannot use .* in argument */ ())
+       _ = append(f2()... /* ERROR cannot use ... */ )
+       _ = append(f0(), f1 /* ERROR 2-valued f1 */ ())
+       _ = append(f0(), f2 /* ERROR 2-valued f2 */ ())
+       _ = append(f0(), f1 /* ERROR 2-valued f1 */ ()...)
+       _ = append(f0(), f2 /* ERROR 2-valued f2 */ ()...)
+
+       // variadic user-defined function
+       append_(f0())
+       append_(f0(), f0()...)
+       append_(f1())
+       append_(f2 /* ERROR cannot use .* in argument */ ())
+       append_(f2()... /* ERROR cannot use ... */ )
+       append_(f0(), f1 /* ERROR 2-valued f1 */ ())
+       append_(f0(), f2 /* ERROR 2-valued f2 */ ())
+       append_(f0(), f1 /* ERROR 2-valued f1 */ ()...)
+       append_(f0(), f2 /* ERROR 2-valued f2 */ ()...)
+}
+
+// Check that embedding a non-interface type in an interface results in a good error message.
+func issue10979() {
+       type _ interface {
+               int /* ERROR int is not an interface */
+       }
+       type T struct{}
+       type _ interface {
+               T /* ERROR T is not an interface */
+       }
+       type _ interface {
+               nosuchtype /* ERROR undeclared name: nosuchtype */
+       }
+       type _ interface {
+               fmt.Nosuchtype /* ERROR Nosuchtype not declared by package fmt */
+       }
+       type _ interface {
+               nosuchpkg /* ERROR undeclared name: nosuchpkg */ .Nosuchtype
+       }
+       type I interface {
+               I.m /* ERROR no field or method m */
+               m()
+       }
+}
+
+// issue11347
+// These should not crash.
+var a1, b1 /* ERROR cycle */ , c1 /* ERROR cycle */ b1 = 0 > 0<<""[""[c1]]>c1
+var a2, b2 /* ERROR cycle */ = 0 /* ERROR cannot initialize */ /* ERROR cannot initialize */ > 0<<""[b2]
+var a3, b3 /* ERROR cycle */ = int /* ERROR cannot initialize */ /* ERROR cannot initialize */ (1<<""[b3])
+
+// issue10260
+// Check that error messages explain reason for interface assignment failures.
+type (
+       I0 interface{}
+       I1 interface{ foo() }
+       I2 interface{ foo(x int) }
+       T0 struct{}
+       T1 struct{}
+       T2 struct{}
+)
+
+func (*T1) foo() {}
+func (*T2) foo(x int) {}
+
+func issue10260() {
+       var (
+               i0 I0
+               i1 I1
+               i2 I2
+               t0 *T0
+               t1 *T1
+               t2 *T2
+       )
+
+       var x I1
+       x = T1 /* ERROR cannot use .*: missing method foo \(foo has pointer receiver\) */ {}
+       _ = x /* ERROR .* cannot have dynamic type T1 \(missing method foo \(foo has pointer receiver\)\) */ .(T1)
+
+       T1{}.foo /* ERROR cannot call pointer method foo on T1 */ ()
+       x.Foo /* ERROR "x.Foo undefined \(type I1 has no field or method Foo, but does have foo\)" */ ()
+
+       _ = i2 /* ERROR i2 .* cannot have dynamic type \*T1 \(wrong type for method foo \(have func\(\), want func\(x int\)\)\) */ .(*T1)
+
+       i1 = i0 /* ERROR cannot use .* missing method foo */
+       i1 = t0 /* ERROR cannot use .* missing method foo */
+       i1 = i2 /* ERROR cannot use .* wrong type for method foo */
+       i1 = t2 /* ERROR cannot use .* wrong type for method foo */
+       i2 = i1 /* ERROR cannot use .* wrong type for method foo */
+       i2 = t1 /* ERROR cannot use .* wrong type for method foo */
+
+       _ = func() I1 { return i0 /* ERROR cannot use .* missing method foo */ }
+       _ = func() I1 { return t0 /* ERROR cannot use .* missing method foo */ }
+       _ = func() I1 { return i2 /* ERROR cannot use .* wrong type for method foo */ }
+       _ = func() I1 { return t2 /* ERROR cannot use .* wrong type for method foo */ }
+       _ = func() I2 { return i1 /* ERROR cannot use .* wrong type for method foo */ }
+       _ = func() I2 { return t1 /* ERROR cannot use .* wrong type for method foo */ }
+
+       // a few more - less exhaustive now
+
+       f := func(I1, I2){}
+       f(i0 /* ERROR cannot use .* missing method foo */ , i1 /* ERROR cannot use .* wrong type for method foo \(have func\(\), want func\(x int\)\) */ )
+
+       _ = [...]I1{i0 /* ERROR cannot use .* missing method foo */ }
+       _ = [...]I1{i2 /* ERROR cannot use .* wrong type for method foo */ }
+       _ = []I1{i0 /* ERROR cannot use .* missing method foo */ }
+       _ = []I1{i2 /* ERROR cannot use .* wrong type for method foo */ }
+       _ = map[int]I1{0: i0 /* ERROR cannot use .* missing method foo */ }
+       _ = map[int]I1{0: i2 /* ERROR cannot use .* wrong type for method foo */ }
+
+       make(chan I1) <- i0 /* ERROR cannot use .* in send: missing method foo */
+       make(chan I1) <- i2 /* ERROR cannot use .* in send: wrong type for method foo */
+}
+
+// Check that constants representable as integers are in integer form
+// before being used in operations that are only defined on integers.
+func issue14229() {
+       // from the issue
+       const _ = int64(-1<<63) % 1e6
+
+       // related
+       const (
+               a int = 3
+               b = 4.0
+               _ = a / b
+               _ = a % b
+               _ = b / a
+               _ = b % a
+       )
+}
+
+// Check that in a n:1 variable declaration with type and initialization
+// expression the type is distributed to all variables of the lhs before
+// the initialization expression assignment is checked.
+func issue15755() {
+       // from issue
+       var i interface{}
+       type b bool
+       var x, y b = i.(b)
+       _ = x == y
+
+       // related: we should see an error since the result of f1 is ([]int, int)
+       var u, v []int = f1 /* ERROR cannot use f1 */ ()
+       _ = u
+       _ = v
+}
+
+// Test that we don't get "declared but not used"
+// errors in the context of invalid/C objects.
+func issue20358() {
+       var F C /* ERROR "undeclared" */ .F
+       var A C /* ERROR "undeclared" */ .A
+       var S C /* ERROR "undeclared" */ .S
+       type T C /* ERROR "undeclared" */ .T
+       type P C /* ERROR "undeclared" */ .P
+
+       // these variables must be "used" even though
+       // the LHS expressions/types below in which
+       // context they are used are unknown/invalid
+       var f, a, s1, s2, s3, t, p int
+
+       _ = F(f)
+       _ = A[a]
+       _ = S[s1:s2:s3]
+       _ = T{t}
+       _ = P{f: p}
+}
+
+// Test that we don't declare lhs variables in short variable
+// declarations before we type-check function literals on the
+// rhs.
+func issue24026() {
+       f := func() int { f(0) /* must refer to outer f */; return 0 }
+       _ = f
+
+       _ = func() {
+               f := func() { _ = f() /* must refer to outer f */ }
+               _ = f
+       }
+
+       // b and c must not be visible inside function literal
+       a := 0
+       a, b, c := func() (int, int, int) {
+               return a, b /* ERROR undeclared */ , c /* ERROR undeclared */
+       }()
+       _, _ = b, c
+}
+
+func f(int) {} // for issue24026
+
+// Test that we don't report a "missing return statement" error
+// (due to incorrect context when type-checking interfaces).
+func issue24140(x interface{}) int {
+        switch x.(type) {
+        case interface{}:
+                return 0
+        default:
+                panic(0)
+        }
+}
+
+// Test that we don't crash when the 'if' condition is missing.
+func issue25438() {
+       if { /* ERROR missing condition */ }
+       if x := 0; /* ERROR missing condition */ { _ = x }
+       if
+       { /* ERROR missing condition */ }
+}
+
+// Test that we can embed alias type names in interfaces.
+type issue25301 interface {
+       E
+}
+
+type E = interface {
+       m()
+}
+
+// Test case from issue.
+// cmd/compile reports a cycle as well.
+type issue25301b /* ERROR cycle */ = interface {
+       m() interface{ issue25301b }
+}
+
+type issue25301c interface {
+       notE // ERROR struct\{\} is not an interface
+}
+
+type notE = struct{}
+
+// Test that method declarations don't introduce artificial cycles
+// (issue #26124).
+const CC TT = 1
+type TT int
+func (TT) MM() [CC]TT
+
+// Reduced test case from issue #26124.
+const preloadLimit LNumber = 128
+type LNumber float64
+func (LNumber) assertFunction() *LFunction
+type LFunction struct {
+       GFunction LGFunction
+}
+type LGFunction func(*LState)
+type LState struct {
+       reg *registry
+}
+type registry struct {
+       alloc *allocator
+}
+type allocator struct {
+       _ [int(preloadLimit)]int
+}
+
+// Test that we don't crash when type-checking composite literals
+// containing errors in the type.
+var issue27346 = [][n /* ERROR undeclared */ ]int{
+       0: {},
+}
+
+var issue22467 = map[int][... /* ERROR invalid use of ... */ ]int{0: {}}
+
+// Test that invalid use of ... in parameter lists is recognized
+// (issue #28281).
+func issue28281a(int, int, ...int)
+func issue28281b(a, b int, c ...int)
+func issue28281c(a, b, c ... /* ERROR can only use ... with final parameter */ int)
+func issue28281d(... /* ERROR can only use ... with final parameter */ int, int)
+func issue28281e(a, b, c  ... /* ERROR can only use ... with final parameter */ int, d int)
+func issue28281f(... /* ERROR can only use ... with final parameter */ int, ... /* ERROR can only use ... with final parameter */ int, int)
+func (... /* ERROR can only use ... with final parameter in list */ TT) f()
+func issue28281g() (... /* ERROR can only use ... with final parameter in list */ TT)
+
+// Issue #26234: Make various field/method lookup errors easier to read by matching cmd/compile's output
+func issue26234a(f *syn.File) {
+       // The error message below should refer to the actual package name (syntax)
+       // not the local package name (syn).
+       f.foo /* ERROR f.foo undefined \(type \*syntax.File has no field or method foo\) */
+}
+
+type T struct {
+       x int
+       E1
+       E2
+}
+
+type E1 struct{ f int }
+type E2 struct{ f int }
+
+func issue26234b(x T) {
+       _ = x.f /* ERROR ambiguous selector x.f */
+}
+
+func issue26234c() {
+       T.x /* ERROR T.x undefined \(type T has no method x\) */ ()
+}
+
+func issue35895() {
+       // T is defined in this package, don't qualify its name with the package name.
+       var _ T = 0 // ERROR cannot convert 0 \(untyped int constant\) to T
+
+       // There is only one package with name syntax imported, only use the (global) package name in error messages.
+       var _ *syn.File = 0 // ERROR cannot convert 0 \(untyped int constant\) to \*syntax.File
+
+       // Because both t1 and t2 have the same global package name (template),
+       // qualify packages with full path name in this case.
+       var _ t1.Template = t2 /* ERROR cannot use .* \(value of type "html/template".Template\) as "text/template".Template */ .Template{}
+}
diff --git a/src/cmd/compile/internal/types2/testdata/labels.src b/src/cmd/compile/internal/types2/testdata/labels.src
new file mode 100644 (file)
index 0000000..9f42406
--- /dev/null
@@ -0,0 +1,207 @@
+// Copyright 2011 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.
+
+// This file is a modified concatenation of the files
+// $GOROOT/test/label.go and $GOROOT/test/label1.go.
+
+package labels
+
+var x int
+
+func f0() {
+L1 /* ERROR "label L1 declared but not used" */ :
+       for {
+       }
+L2 /* ERROR "label L2 declared but not used" */ :
+       select {
+       }
+L3 /* ERROR "label L3 declared but not used" */ :
+       switch {
+       }
+L4 /* ERROR "label L4 declared but not used" */ :
+       if true {
+       }
+L5 /* ERROR "label L5 declared but not used" */ :
+       f0()
+L6:
+       f0()
+L6 /* ERROR "label L6 already declared" */ :
+       f0()
+       if x == 20 {
+               goto L6
+       }
+
+L7:
+       for {
+               break L7
+               break L8 /* ERROR "invalid break label L8" */
+       }
+
+// A label must be directly associated with a switch, select, or
+// for statement; it cannot be the label of a labeled statement.
+
+L7a /* ERROR "declared but not used" */ : L7b:
+       for {
+               break L7a /* ERROR "invalid break label L7a" */
+               continue L7a /* ERROR "invalid continue label L7a" */
+               continue L7b
+       }
+
+L8:
+       for {
+               if x == 21 {
+                       continue L8
+                       continue L7 /* ERROR "invalid continue label L7" */
+               }
+       }
+
+L9:
+       switch {
+       case true:
+               break L9
+       defalt /* ERROR "label defalt declared but not used" */ :
+       }
+
+L10:
+       select {
+       default:
+               break L10
+               break L9 /* ERROR "invalid break label L9" */
+       }
+
+       goto L10a
+L10a: L10b:
+       select {
+       default:
+               break L10a /* ERROR "invalid break label L10a" */
+               break L10b
+               continue L10b /* ERROR "invalid continue label L10b" */
+       }
+}
+
+func f1() {
+L1:
+       for {
+               if x == 0 {
+                       break L1
+               }
+               if x == 1 {
+                       continue L1
+               }
+               goto L1
+       }
+
+L2:
+       select {
+       default:
+               if x == 0 {
+                       break L2
+               }
+               if x == 1 {
+                       continue L2 /* ERROR "invalid continue label L2" */
+               }
+               goto L2
+       }
+
+L3:
+       switch {
+       case x > 10:
+               if x == 11 {
+                       break L3
+               }
+               if x == 12 {
+                       continue L3 /* ERROR "invalid continue label L3" */
+               }
+               goto L3
+       }
+
+L4:
+       if true {
+               if x == 13 {
+                       break L4 /* ERROR "invalid break label L4" */
+               }
+               if x == 14 {
+                       continue L4 /* ERROR "invalid continue label L4" */
+               }
+               if x == 15 {
+                       goto L4
+               }
+       }
+
+L5:
+       f1()
+       if x == 16 {
+               break L5 /* ERROR "invalid break label L5" */
+       }
+       if x == 17 {
+               continue L5 /* ERROR "invalid continue label L5" */
+       }
+       if x == 18 {
+               goto L5
+       }
+
+       for {
+               if x == 19 {
+                       break L1 /* ERROR "invalid break label L1" */
+               }
+               if x == 20 {
+                       continue L1 /* ERROR "invalid continue label L1" */
+               }
+               if x == 21 {
+                       goto L1
+               }
+       }
+}
+
+// Additional tests not in the original files.
+
+func f2() {
+L1 /* ERROR "label L1 declared but not used" */ :
+       if x == 0 {
+               for {
+                       continue L1 /* ERROR "invalid continue label L1" */
+               }
+       }
+}
+
+func f3() {
+L1:
+L2:
+L3:
+       for {
+               break L1 /* ERROR "invalid break label L1" */
+               break L2 /* ERROR "invalid break label L2" */
+               break L3
+               continue L1 /* ERROR "invalid continue label L1" */
+               continue L2 /* ERROR "invalid continue label L2" */
+               continue L3
+               goto L1
+               goto L2
+               goto L3
+       }
+}
+
+// Blank labels are never declared.
+
+func f4() {
+_:
+_: // multiple blank labels are ok
+       goto _ /* ERROR "label _ not declared" */
+}
+
+func f5() {
+_:
+       for {
+               break _ /* ERROR "invalid break label _" */
+               continue _ /* ERROR "invalid continue label _" */
+       }
+}
+
+func f6() {
+_:
+       switch {
+       default:
+               break _ /* ERROR "invalid break label _" */
+       }
+}
diff --git a/src/cmd/compile/internal/types2/testdata/linalg.go2 b/src/cmd/compile/internal/types2/testdata/linalg.go2
new file mode 100644 (file)
index 0000000..0d27603
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright 2019 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 linalg
+
+import "math"
+
+// Numeric is type bound that matches any numeric type.
+// It would likely be in a constraints package in the standard library.
+type Numeric interface {
+       type int, int8, int16, int32, int64,
+               uint, uint8, uint16, uint32, uint64, uintptr,
+               float32, float64,
+               complex64, complex128
+}
+
+func DotProduct[T Numeric](s1, s2 []T) T {
+       if len(s1) != len(s2) {
+               panic("DotProduct: slices of unequal length")
+       }
+       var r T
+       for i := range s1 {
+               r += s1[i] * s2[i]
+       }
+       return r
+}
+
+// NumericAbs matches numeric types with an Abs method.
+type NumericAbs[T any] interface {
+       Numeric
+
+       Abs() T
+}
+
+// AbsDifference computes the absolute value of the difference of
+// a and b, where the absolute value is determined by the Abs method.
+func AbsDifference[T NumericAbs[T]](a, b T) T {
+       d := a - b
+       return d.Abs()
+}
+
+// OrderedNumeric is a type bound that matches numeric types that support the < operator.
+type OrderedNumeric interface {
+       type int, int8, int16, int32, int64,
+               uint, uint8, uint16, uint32, uint64, uintptr,
+               float32, float64
+}
+
+// Complex is a type bound that matches the two complex types, which do not have a < operator.
+type Complex interface {
+       type complex64, complex128
+}
+
+// OrderedAbs is a helper type that defines an Abs method for
+// ordered numeric types.
+type OrderedAbs[T OrderedNumeric] T
+
+func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
+       if a < 0 {
+               return -a
+       }
+       return a
+}
+
+// ComplexAbs is a helper type that defines an Abs method for
+// complex types.
+type ComplexAbs[T Complex] T
+
+func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
+       r := float64(real(a))
+       i := float64(imag(a))
+       d := math.Sqrt(r * r + i * i)
+       return ComplexAbs[T](complex(d, 0))
+}
+
+func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
+       return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
+}
+
+func ComplexAbsDifference[T Complex](a, b T) T {
+       return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
+}
diff --git a/src/cmd/compile/internal/types2/testdata/literals.src b/src/cmd/compile/internal/types2/testdata/literals.src
new file mode 100644 (file)
index 0000000..494a465
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright 2019 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.
+
+// This file tests various representations of literals
+// and compares them with literals or constant expressions
+// of equal values.
+
+package literals
+
+func _() {
+       // 0-octals
+       assert(0_123 == 0123)
+       assert(0123_456 == 0123456)
+
+       // decimals
+       assert(1_234 == 1234)
+       assert(1_234_567 == 1234567)
+
+       // hexadecimals
+       assert(0X_0 == 0)
+       assert(0X_1234 == 0x1234)
+       assert(0X_CAFE_f00d == 0xcafef00d)
+
+       // octals
+       assert(0o0 == 0)
+       assert(0o1234 == 01234)
+       assert(0o01234567 == 01234567)
+
+       assert(0O0 == 0)
+       assert(0O1234 == 01234)
+       assert(0O01234567 == 01234567)
+
+       assert(0o_0 == 0)
+       assert(0o_1234 == 01234)
+       assert(0o0123_4567 == 01234567)
+
+       assert(0O_0 == 0)
+       assert(0O_1234 == 01234)
+       assert(0O0123_4567 == 01234567)
+
+       // binaries
+       assert(0b0 == 0)
+       assert(0b1011 == 0xb)
+       assert(0b00101101 == 0x2d)
+
+       assert(0B0 == 0)
+       assert(0B1011 == 0xb)
+       assert(0B00101101 == 0x2d)
+
+       assert(0b_0 == 0)
+       assert(0b10_11 == 0xb)
+       assert(0b_0010_1101 == 0x2d)
+
+       // decimal floats
+       assert(1_2_3. == 123.)
+       assert(0_123. == 123.)
+
+       assert(0_0e0 == 0.)
+       assert(1_2_3e0 == 123.)
+       assert(0_123e0 == 123.)
+
+       assert(0e-0_0 == 0.)
+       assert(1_2_3E+0 == 123.)
+       assert(0123E1_2_3 == 123e123)
+
+       assert(0.e+1 == 0.)
+       assert(123.E-1_0 == 123e-10)
+       assert(01_23.e123 == 123e123)
+
+       assert(.0e-1 == .0)
+       assert(.123E+10 == .123e10)
+       assert(.0123E123 == .0123e123)
+
+       assert(1_2_3.123 == 123.123)
+       assert(0123.01_23 == 123.0123)
+
+       // hexadecimal floats
+       assert(0x0.p+0 == 0.)
+       assert(0Xdeadcafe.p-10 == 0xdeadcafe/1024.0)
+       assert(0x1234.P84 == 0x1234000000000000000000000)
+
+       assert(0x.1p-0 == 1./16)
+       assert(0X.deadcafep4 == 1.0*0xdeadcafe/0x10000000)
+       assert(0x.1234P+12 == 1.0*0x1234/0x10)
+
+       assert(0x0p0 == 0.)
+       assert(0Xdeadcafep+1 == 0x1bd5b95fc)
+       assert(0x1234P-10 == 0x1234/1024.0)
+
+       assert(0x0.0p0 == 0.)
+       assert(0Xdead.cafep+1 == 1.0*0x1bd5b95fc/0x10000)
+       assert(0x12.34P-10 == 1.0*0x1234/0x40000)
+
+       assert(0Xdead_cafep+1 == 0xdeadcafep+1)
+       assert(0x_1234P-10 == 0x1234p-10)
+
+       assert(0X_dead_cafe.p-10 == 0xdeadcafe.p-10)
+       assert(0x12_34.P1_2_3 == 0x1234.p123)
+
+       assert(1_234i == 1234i)
+       assert(1_234_567i == 1234567i)
+
+       assert(0.i == 0i)
+       assert(123.i == 123i)
+       assert(0123.i == 123i)
+
+       assert(0.e+1i == 0i)
+       assert(123.E-1_0i == 123e-10i)
+       assert(01_23.e123i == 123e123i)
+}
diff --git a/src/cmd/compile/internal/types2/testdata/main.go2 b/src/cmd/compile/internal/types2/testdata/main.go2
new file mode 100644 (file)
index 0000000..b7ddeaa
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2020 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
+
+func /* ERROR "func main must have no type parameters" */ main[T any]() {}
diff --git a/src/cmd/compile/internal/types2/testdata/main.src b/src/cmd/compile/internal/types2/testdata/main.src
new file mode 100644 (file)
index 0000000..f892938
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2020 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
+
+func main()
+func /* ERROR "no arguments and no return values" */ main /* ERROR redeclared */ (int)
+func /* ERROR "no arguments and no return values" */ main /* ERROR redeclared */ () int
diff --git a/src/cmd/compile/internal/types2/testdata/map.go2 b/src/cmd/compile/internal/types2/testdata/map.go2
new file mode 100644 (file)
index 0000000..814d953
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2019 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 orderedmap provides an ordered map, implemented as a binary tree.
+package orderedmap
+
+// TODO(gri) fix imports for tests
+import "chans" // ERROR could not import
+
+// Map is an ordered map.
+type Map[K, V any] struct {
+       root    *node[K, V]
+       compare func(K, K) int
+}
+
+// node is the type of a node in the binary tree.
+type node[K, V any] struct {
+       key         K
+       val         V
+       left, right *node[K, V]
+}
+
+// New returns a new map.
+func New[K, V any](compare func(K, K) int) *Map[K, V] {
+        return &Map[K, V]{compare: compare}
+}
+
+// find looks up key in the map, and returns either a pointer
+// to the node holding key, or a pointer to the location where
+// such a node would go.
+func (m *Map[K, V]) find(key K) **node[K, V] {
+       pn := &m.root
+       for *pn != nil {
+               switch cmp := m.compare(key, (*pn).key); {
+               case cmp < 0:
+                       pn = &(*pn).left
+               case cmp > 0:
+                       pn = &(*pn).right
+               default:
+                       return pn
+               }
+       }
+       return pn
+}
+
+// Insert inserts a new key/value into the map.
+// If the key is already present, the value is replaced.
+// Returns true if this is a new key, false if already present.
+func (m *Map[K, V]) Insert(key K, val V) bool {
+       pn := m.find(key)
+       if *pn != nil {
+               (*pn).val = val
+               return false
+       }
+        *pn = &node[K, V]{key: key, val: val}
+       return true
+}
+
+// Find returns the value associated with a key, or zero if not present.
+// The found result reports whether the key was found.
+func (m *Map[K, V]) Find(key K) (V, bool) {
+       pn := m.find(key)
+       if *pn == nil {
+               var zero V // see the discussion of zero values, above
+               return zero, false
+       }
+       return (*pn).val, true
+}
+
+// keyValue is a pair of key and value used when iterating.
+type keyValue[K, V any] struct {
+       key K
+       val V
+}
+
+// InOrder returns an iterator that does an in-order traversal of the map.
+func (m *Map[K, V]) InOrder() *Iterator[K, V] {
+       sender, receiver := chans.Ranger[keyValue[K, V]]()
+       var f func(*node[K, V]) bool
+       f = func(n *node[K, V]) bool {
+               if n == nil {
+                       return true
+               }
+               // Stop sending values if sender.Send returns false,
+               // meaning that nothing is listening at the receiver end.
+               return f(n.left) &&
+                        sender.Send(keyValue[K, V]{n.key, n.val}) &&
+                       f(n.right)
+       }
+       go func() {
+               f(m.root)
+               sender.Close()
+       }()
+       return &Iterator[K, V]{receiver}
+}
+
+// Iterator is used to iterate over the map.
+type Iterator[K, V any] struct {
+       r *chans.Receiver[keyValue[K, V]]
+}
+
+// Next returns the next key and value pair, and a boolean indicating
+// whether they are valid or whether we have reached the end.
+func (it *Iterator[K, V]) Next() (K, V, bool) {
+       keyval, ok := it.r.Next()
+       if !ok {
+               var zerok K
+               var zerov V
+               return zerok, zerov, false
+       }
+       return keyval.key, keyval.val, true
+}
diff --git a/src/cmd/compile/internal/types2/testdata/map2.go2 b/src/cmd/compile/internal/types2/testdata/map2.go2
new file mode 100644 (file)
index 0000000..2833445
--- /dev/null
@@ -0,0 +1,146 @@
+// Copyright 2019 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.
+
+// This file is like map.go2, but instead if importing chans, it contains
+// the necessary functionality at the end of the file.
+
+// Package orderedmap provides an ordered map, implemented as a binary tree.
+package orderedmap
+
+// Map is an ordered map.
+type Map[K, V any] struct {
+       root    *node[K, V]
+       compare func(K, K) int
+}
+
+// node is the type of a node in the binary tree.
+type node[K, V any] struct {
+       key         K
+       val         V
+       left, right *node[K, V]
+}
+
+// New returns a new map.
+func New[K, V any](compare func(K, K) int) *Map[K, V] {
+        return &Map[K, V]{compare: compare}
+}
+
+// find looks up key in the map, and returns either a pointer
+// to the node holding key, or a pointer to the location where
+// such a node would go.
+func (m *Map[K, V]) find(key K) **node[K, V] {
+       pn := &m.root
+       for *pn != nil {
+               switch cmp := m.compare(key, (*pn).key); {
+               case cmp < 0:
+                       pn = &(*pn).left
+               case cmp > 0:
+                       pn = &(*pn).right
+               default:
+                       return pn
+               }
+       }
+       return pn
+}
+
+// Insert inserts a new key/value into the map.
+// If the key is already present, the value is replaced.
+// Returns true if this is a new key, false if already present.
+func (m *Map[K, V]) Insert(key K, val V) bool {
+       pn := m.find(key)
+       if *pn != nil {
+               (*pn).val = val
+               return false
+       }
+       *pn = &node[K, V]{key: key, val: val}
+       return true
+}
+
+// Find returns the value associated with a key, or zero if not present.
+// The found result reports whether the key was found.
+func (m *Map[K, V]) Find(key K) (V, bool) {
+       pn := m.find(key)
+       if *pn == nil {
+               var zero V // see the discussion of zero values, above
+               return zero, false
+       }
+       return (*pn).val, true
+}
+
+// keyValue is a pair of key and value used when iterating.
+type keyValue[K, V any] struct {
+       key K
+       val V
+}
+
+// InOrder returns an iterator that does an in-order traversal of the map.
+func (m *Map[K, V]) InOrder() *Iterator[K, V] {
+       sender, receiver := chans_Ranger[keyValue[K, V]]()
+       var f func(*node[K, V]) bool
+       f = func(n *node[K, V]) bool {
+               if n == nil {
+                       return true
+               }
+               // Stop sending values if sender.Send returns false,
+               // meaning that nothing is listening at the receiver end.
+               return f(n.left) &&
+                        sender.Send(keyValue[K, V]{n.key, n.val}) &&
+                       f(n.right)
+       }
+       go func() {
+               f(m.root)
+               sender.Close()
+       }()
+       return &Iterator[K, V]{receiver}
+}
+
+// Iterator is used to iterate over the map.
+type Iterator[K, V any] struct {
+       r *chans_Receiver[keyValue[K, V]]
+}
+
+// Next returns the next key and value pair, and a boolean indicating
+// whether they are valid or whether we have reached the end.
+func (it *Iterator[K, V]) Next() (K, V, bool) {
+       keyval, ok := it.r.Next()
+       if !ok {
+               var zerok K
+               var zerov V
+               return zerok, zerov, false
+       }
+       return keyval.key, keyval.val, true
+}
+
+// chans
+
+func chans_Ranger[T any]() (*chans_Sender[T], *chans_Receiver[T])
+
+// A sender is used to send values to a Receiver.
+type chans_Sender[T any] struct {
+       values chan<- T
+       done <-chan bool
+}
+
+func (s *chans_Sender[T]) Send(v T) bool {
+       select {
+       case s.values <- v:
+               return true
+       case <-s.done:
+               return false
+       }
+}
+
+func (s *chans_Sender[T]) Close() {
+       close(s.values)
+}
+
+type chans_Receiver[T any] struct {
+       values <-chan T
+       done chan<- bool
+}
+
+func (r *chans_Receiver[T]) Next() (T, bool) {
+       v, ok := <-r.values
+       return v, ok
+}
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/testdata/methodsets.src b/src/cmd/compile/internal/types2/testdata/methodsets.src
new file mode 100644 (file)
index 0000000..9fb10de
--- /dev/null
@@ -0,0 +1,214 @@
+// Copyright 2013 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 methodsets
+
+type T0 struct {}
+
+func (T0) v0() {}
+func (*T0) p0() {}
+
+type T1 struct {} // like T0 with different method names
+
+func (T1) v1() {}
+func (*T1) p1() {}
+
+type T2 interface {
+       v2()
+       p2()
+}
+
+type T3 struct {
+       T0
+       *T1
+       T2
+}
+
+// Method expressions
+func _() {
+       var (
+               _ func(T0) = T0.v0
+               _ = T0.p0 /* ERROR "cannot call pointer method p0 on T0" */
+
+               _ func (*T0) = (*T0).v0
+               _ func (*T0) = (*T0).p0
+
+               // T1 is like T0
+
+               _ func(T2) = T2.v2
+               _ func(T2) = T2.p2
+
+               _ func(T3) = T3.v0
+               _ func(T3) = T3.p0 /* ERROR "cannot call pointer method p0 on T3" */
+               _ func(T3) = T3.v1
+               _ func(T3) = T3.p1
+               _ func(T3) = T3.v2
+               _ func(T3) = T3.p2
+
+               _ func(*T3) = (*T3).v0
+               _ func(*T3) = (*T3).p0
+               _ func(*T3) = (*T3).v1
+               _ func(*T3) = (*T3).p1
+               _ func(*T3) = (*T3).v2
+               _ func(*T3) = (*T3).p2
+       )
+}
+
+// Method values with addressable receivers
+func _() {
+       var (
+               v0 T0
+               _ func() = v0.v0
+               _ func() = v0.p0
+       )
+
+       var (
+               p0 *T0
+               _ func() = p0.v0
+               _ func() = p0.p0
+       )
+
+       // T1 is like T0
+
+       var (
+               v2 T2
+               _ func() = v2.v2
+               _ func() = v2.p2
+       )
+
+       var (
+               v4 T3
+               _ func() = v4.v0
+               _ func() = v4.p0
+               _ func() = v4.v1
+               _ func() = v4.p1
+               _ func() = v4.v2
+               _ func() = v4.p2
+       )
+
+       var (
+               p4 *T3
+               _ func() = p4.v0
+               _ func() = p4.p0
+               _ func() = p4.v1
+               _ func() = p4.p1
+               _ func() = p4.v2
+               _ func() = p4.p2
+       )
+}
+
+// Method calls with addressable receivers
+func _() {
+       var v0 T0
+       v0.v0()
+       v0.p0()
+
+       var p0 *T0
+       p0.v0()
+       p0.p0()
+
+       // T1 is like T0
+
+       var v2 T2
+       v2.v2()
+       v2.p2()
+
+       var v4 T3
+       v4.v0()
+       v4.p0()
+       v4.v1()
+       v4.p1()
+       v4.v2()
+       v4.p2()
+
+       var p4 *T3
+       p4.v0()
+       p4.p0()
+       p4.v1()
+       p4.p1()
+       p4.v2()
+       p4.p2()
+}
+
+// Method values with value receivers
+func _() {
+       var (
+               _ func() = T0{}.v0
+               _ func() = T0{}.p0 /* ERROR "cannot call pointer method p0 on T0" */
+
+               _ func() = (&T0{}).v0
+               _ func() = (&T0{}).p0
+
+               // T1 is like T0
+
+               // no values for T2
+
+               _ func() = T3{}.v0
+               _ func() = T3{}.p0 /* ERROR "cannot call pointer method p0 on T3" */
+               _ func() = T3{}.v1
+               _ func() = T3{}.p1
+               _ func() = T3{}.v2
+               _ func() = T3{}.p2
+
+               _ func() = (&T3{}).v0
+               _ func() = (&T3{}).p0
+               _ func() = (&T3{}).v1
+               _ func() = (&T3{}).p1
+               _ func() = (&T3{}).v2
+               _ func() = (&T3{}).p2
+       )
+}
+
+// Method calls with value receivers
+func _() {
+       T0{}.v0()
+       T0{}.p0 /* ERROR "cannot call pointer method p0 on T0" */ ()
+
+       (&T0{}).v0()
+       (&T0{}).p0()
+
+       // T1 is like T0
+
+       // no values for T2
+
+       T3{}.v0()
+       T3{}.p0 /* ERROR "cannot call pointer method p0 on T3" */ ()
+       T3{}.v1()
+       T3{}.p1()
+       T3{}.v2()
+       T3{}.p2()
+
+       (&T3{}).v0()
+       (&T3{}).p0()
+       (&T3{}).v1()
+       (&T3{}).p1()
+       (&T3{}).v2()
+       (&T3{}).p2()
+}
+
+// *T has no methods if T is an interface type
+func issue5918() {
+       var (
+               err error
+               _ = err.Error()
+               _ func() string = err.Error
+               _ func(error) string = error.Error
+
+               perr = &err
+               _ = perr.Error /* ERROR "no field or method" */ ()
+               _ func() string = perr.Error /* ERROR "no field or method" */
+               _ func(*error) string = (*error).Error /* ERROR "no field or method" */
+       )
+
+       type T *interface{ m() int }
+       var (
+               x T
+               _ = (*x).m()
+               _ = (*x).m
+
+               _ = x.m /* ERROR "no field or method" */ ()
+               _ = x.m /* ERROR "no field or method" */
+               _ = T.m /* ERROR "no field or method" */
+       )
+}
diff --git a/src/cmd/compile/internal/types2/testdata/mtypeparams.go2 b/src/cmd/compile/internal/types2/testdata/mtypeparams.go2
new file mode 100644 (file)
index 0000000..c2f282b
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2020 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.
+
+// If types2.Config.AcceptMethodTypeParams is set,
+// the type checker accepts methods that have their
+// own type parameter list.
+
+package p
+
+type S struct{}
+
+func (S) m[T any](v T)
+
+// TODO(gri) Once we collect interface method type parameters
+//           in the parser, we can enable these tests again.
+/*
+type I interface {
+   m[T any](v T)
+}
+
+type J interface {
+   m[T any](v T)
+}
+
+var _ I = S{}
+var _ I = J(nil)
+
+type C interface{ n() }
+
+type Sc struct{}
+
+func (Sc) m[T C](v T)
+
+type Ic interface {
+   m[T C](v T)
+}
+
+type Jc interface {
+   m[T C](v T)
+}
+
+var _ Ic = Sc{}
+var _ Ic = Jc(nil)
+
+// TODO(gri) These should fail because the constraints don't match.
+var _ I = Sc{}
+var _ I = Jc(nil)
+
+var _ Ic = S{}
+var _ Ic = J(nil)
+*/
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/testdata/shifts.src b/src/cmd/compile/internal/types2/testdata/shifts.src
new file mode 100644 (file)
index 0000000..04a679f
--- /dev/null
@@ -0,0 +1,396 @@
+// Copyright 2013 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 shifts
+
+func shifts0() {
+       // basic constant shifts
+       const (
+               s = 10
+               _ = 0<<0
+               _ = 1<<s
+               _ = 1<<- /* ERROR "negative shift count" */ 1
+               // For the test below we may decide to convert to int
+               // rather than uint and then report a negative shift
+               // count instead, which might be a better error. The
+               // (minor) difference is that this would restrict the
+               // shift count range by half (from all uint values to
+               // the positive int values).
+               // This depends on the exact spec wording which is not
+               // done yet.
+               // TODO(gri) revisit and adjust when spec change is done
+               _ = 1<<- /* ERROR "truncated to uint" */ 1.0
+               _ = 1<<1075 /* ERROR "invalid shift" */
+               _ = 2.0<<1
+               _ = 1<<1.0
+               _ = 1<<(1+0i)
+
+               _ int = 2<<s
+               _ float32 = 2<<s
+               _ complex64 = 2<<s
+
+               _ int = 2.0<<s
+               _ float32 = 2.0<<s
+               _ complex64 = 2.0<<s
+
+               _ int = 'a'<<s
+               _ float32 = 'a'<<s
+               _ complex64 = 'a'<<s
+       )
+}
+
+func shifts1() {
+       // basic non-constant shifts
+       var (
+               i int
+               u uint
+
+               _ = 1<<0
+               _ = 1<<i
+               _ = 1<<u
+               _ = 1<<"foo" /* ERROR "cannot convert" */
+               _ = i<<0
+               _ = i<<- /* ERROR "negative shift count" */ 1
+               _ = i<<1.0
+               _ = 1<<(1+0i)
+               _ = 1 /* ERROR "overflows" */ <<100
+
+               _ uint = 1 << 0
+               _ uint = 1 << u
+               _ float32 = 1 /* ERROR "must be integer" */ << u
+
+               // for issue 14822
+               _ = 1<<( /* ERROR "invalid shift count" */ 1<<64-1)
+               _ = 1<<( /* ERROR "invalid shift count" */ 1<<64)
+               _ = u<<(1<<63) // valid
+               _ = u<<(1<<64) // valid
+       )
+}
+
+func shifts2() {
+       // from the spec
+       var (
+               s uint = 33
+               i = 1<<s           // 1 has type int
+               j int32 = 1<<s     // 1 has type int32; j == 0
+               k = uint64(1<<s)   // 1 has type uint64; k == 1<<33
+               m int = 1.0<<s     // 1.0 has type int
+               n = 1.0<<s != i    // 1.0 has type int; n == false if ints are 32bits in size
+               o = 1<<s == 2<<s   // 1 and 2 have type int; o == true if ints are 32bits in size
+               p = 1<<s == 1<<33  // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
+               u = 1.0 /* ERROR "must be integer" */ <<s         // illegal: 1.0 has type float64, cannot shift
+               u1 = 1.0 /* ERROR "must be integer" */ <<s != 0   // illegal: 1.0 has type float64, cannot shift
+               u2 = 1 /* ERROR "must be integer" */ <<s != 1.0   // illegal: 1 has type float64, cannot shift
+               v float32 = 1 /* ERROR "must be integer" */ <<s   // illegal: 1 has type float32, cannot shift
+               w int64 = 1.0<<33  // 1.0<<33 is a constant shift expression
+       )
+       _, _, _, _, _, _, _, _, _, _, _, _ = i, j, k, m, n, o, p, u, u1, u2, v, w
+}
+
+func shifts3(a int16, b float32) {
+       // random tests
+       var (
+               s uint = 11
+               u = 1 /* ERROR "must be integer" */ <<s + 1.0
+               v complex128 = 1 /* ERROR "must be integer" */ << s + 1.0 /* ERROR "must be integer" */ << s + 1
+       )
+       x := 1.0 /* ERROR "must be integer" */ <<s + 1
+       shifts3(1.0 << s, 1 /* ERROR "must be integer" */ >> s)
+       _, _, _ = u, v, x
+}
+
+func shifts4() {
+       // shifts in comparisons w/ untyped operands
+       var s uint
+
+       _ = 1<<s == 1
+       _ = 1 /* ERROR "integer" */ <<s == 1.
+       _ = 1. /* ERROR "integer" */ <<s == 1
+       _ = 1. /* ERROR "integer" */ <<s == 1.
+
+       _ = 1<<s + 1 == 1
+       _ = 1 /* ERROR "integer" */ <<s + 1 == 1.
+       _ = 1 /* ERROR "integer" */ <<s + 1. == 1
+       _ = 1 /* ERROR "integer" */ <<s + 1. == 1.
+       _ = 1. /* ERROR "integer" */ <<s + 1 == 1
+       _ = 1. /* ERROR "integer" */ <<s + 1 == 1.
+       _ = 1. /* ERROR "integer" */ <<s + 1. == 1
+       _ = 1. /* ERROR "integer" */ <<s + 1. == 1.
+
+       _ = 1<<s == 1<<s
+       _ = 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
+
+       _ = 1<<s + 1<<s == 1
+       _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
+       _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
+       _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
+       _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1
+       _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
+       _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
+       _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
+
+       _ = 1<<s + 1<<s == 1<<s + 1<<s
+       _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+       _ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+}
+
+func shifts5() {
+       // shifts in comparisons w/ typed operands
+       var s uint
+       var x int
+
+       _ = 1<<s == x
+       _ = 1.<<s == x
+       _ = 1.1 /* ERROR "int" */ <<s == x
+
+       _ = 1<<s + x == 1
+       _ = 1<<s + x == 1.
+       _ = 1<<s + x == 1.1 /* ERROR "int" */
+       _ = 1.<<s + x == 1
+       _ = 1.<<s + x == 1.
+       _ = 1.<<s + x == 1.1 /* ERROR "int" */
+       _ = 1.1 /* ERROR "int" */ <<s + x == 1
+       _ = 1.1 /* ERROR "int" */ <<s + x == 1.
+       _ = 1.1 /* ERROR "int" */ <<s + x == 1.1
+
+       _ = 1<<s == x<<s
+       _ = 1.<<s == x<<s
+       _ = 1.1  /* ERROR "int" */ <<s == x<<s
+}
+
+func shifts6() {
+       // shifts as operands in non-arithmetic operations and as arguments
+       var a [10]int
+       var s uint
+
+       _ = a[1<<s]
+       _ = a[1.0]
+       _ = a[1.0<<s]
+
+       _ = make([]int, 1.0)
+       _ = make([]int, 1.0<<s)
+       _ = make([]int, 1.1 /* ERROR "must be integer" */ <<s)
+
+       _ = float32(1)
+       _ = float32(1 /* ERROR "must be integer" */ <<s)
+       _ = float32(1.0)
+       _ = float32(1.0 /* ERROR "must be integer" */ <<s)
+       _ = float32(1.1 /* ERROR "must be integer" */ <<s)
+
+       // TODO(gri) port fixes from go/types
+       // _ = int32(0x80000000 /* ERROR "overflows int32" */ << s)
+       // TODO(rfindley) Eliminate the redundant error here.
+       // _ = int32(( /* ERROR "truncated to int32" */ 0x80000000 /* ERROR "truncated to int32" */ + 0i) << s)
+
+       _ = int(1+0i<<0)
+       // _ = int((1+0i)<<s)
+       // _ = int(1.0<<s)
+       // _ = int(complex(1, 0)<<s)
+       _ = int(float32/* ERROR "must be integer" */(1.0) <<s)
+       _ = int(1.1 /* ERROR must be integer */ <<s)
+       _ = int(( /* ERROR "must be integer" */ 1+1i)  <<s)
+
+       _ = complex(1 /* ERROR "must be integer" */ <<s, 0)
+
+       var b []int
+       _ = append(b, 1<<s)
+       _ = append(b, 1.0<<s)
+       _ = append(b, (1+0i)<<s)
+       _ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
+       _ = append(b, (1 + 0i) <<s)
+       _ = append(b, ( /* ERROR "must be integer" */ 1 + 1i)  <<s)
+
+       _ = complex(1.0 /* ERROR "must be integer" */ <<s, 0)
+       _ = complex(1.1 /* ERROR "must be integer" */ <<s, 0)
+       _ = complex(0, 1.0 /* ERROR "must be integer" */ <<s)
+       _ = complex(0, 1.1 /* ERROR "must be integer" */ <<s)
+
+       // TODO(gri) The delete below is not type-checked correctly yet.
+       // var m1 map[int]string
+       // delete(m1, 1<<s)
+}
+
+func shifts7() {
+       // shifts of shifts
+       var s uint
+       var x int
+       _ = x
+
+       _ = 1<<(1<<s)
+       _ = 1<<(1.<<s)
+       _ = 1. /* ERROR "integer" */ <<(1<<s)
+       _ = 1. /* ERROR "integer" */ <<(1.<<s)
+
+       x = 1<<(1<<s)
+       x = 1<<(1.<<s)
+       x = 1.<<(1<<s)
+       x = 1.<<(1.<<s)
+
+       _ = (1<<s)<<(1<<s)
+       _ = (1<<s)<<(1.<<s)
+       _ = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
+       _ = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
+
+       x = (1<<s)<<(1<<s)
+       x = (1<<s)<<(1.<<s)
+       x = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
+       x = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
+}
+
+func shifts8() {
+       // shift examples from shift discussion: better error messages
+       var s uint
+       _ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1
+       _ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1.0
+       _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s == 1.0
+       _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.0 == 1
+       _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.1 == 1
+       _ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1 == 1.0
+
+       // additional cases
+       _ = complex(1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s, 1)
+       _ = complex(1.0, 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s)
+
+       _ = int(1.<<s)
+       _ = int(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+       _ = float32(1 /* ERROR "shifted operand .* must be integer" */ <<s)
+       _ = float32(1. /* ERROR "shifted operand .* must be integer" */ <<s)
+       _ = float32(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+       // TODO(gri) the error messages for these two are incorrect - disabled for now
+       // _ = complex64(1<<s)
+       // _ = complex64(1.<<s)
+       _ = complex64(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+}
+
+func shifts9() {
+       // various originally failing snippets of code from the std library
+       // from src/compress/lzw/reader.go:90
+       {
+               var d struct {
+                       bits     uint32
+                       width    uint
+               }
+               _ = uint16(d.bits & (1<<d.width - 1))
+       }
+
+       // from src/debug/dwarf/buf.go:116
+       {
+               var ux uint64
+               var bits uint
+               x := int64(ux)
+               if x&(1<<(bits-1)) != 0 {}
+       }
+
+       // from src/encoding/asn1/asn1.go:160
+       {
+               var bytes []byte
+               if bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {}
+       }
+
+       // from src/math/big/rat.go:140
+       {
+               var exp int
+               var mantissa uint64
+               shift := uint64(-1022 - (exp - 1)) // [1..53)
+               _ = mantissa & (1<<shift - 1)
+       }
+
+       // from src/net/interface.go:51
+       {
+               type Flags uint
+               var f Flags
+               var i int
+               if f&(1<<uint(i)) != 0 {}
+       }
+
+       // from src/runtime/softfloat64.go:234
+       {
+               var gm uint64
+               var shift uint
+               _ = gm & (1<<shift - 1)
+       }
+
+       // from src/strconv/atof.go:326
+       {
+               var mant uint64
+               var mantbits uint
+               if mant == 2<<mantbits {}
+       }
+
+       // from src/route_bsd.go:82
+       {
+               var Addrs int32
+               const rtaRtMask = 1
+               var i uint
+               if Addrs&rtaRtMask&(1<<i) == 0 {}
+       }
+
+       // from src/text/scanner/scanner.go:540
+       {
+               var s struct { Whitespace uint64 }
+               var ch rune
+               for s.Whitespace&(1<<uint(ch)) != 0 {}
+       }
+}
+
+func issue5895() {
+       var x = 'a' << 1 // type of x must be rune
+       var _ rune = x
+}
+
+func issue11325() {
+       var _ = 0 >> 1.1 /* ERROR "truncated to uint" */ // example from issue 11325
+       _ = 0 >> 1.1 /* ERROR "truncated to uint" */
+       _ = 0 << 1.1 /* ERROR "truncated to uint" */
+       _ = 0 >> 1.
+       _ = 1 >> 1.1 /* ERROR "truncated to uint" */
+       _ = 1 >> 1.
+       _ = 1. >> 1
+       _ = 1. >> 1.
+       _ = 1.1 /* ERROR "must be integer" */ >> 1
+}
+
+func issue11594() {
+       var _ = complex64 /* ERROR "must be integer" */ (1) << 2 // example from issue 11594
+       _ = float32 /* ERROR "must be integer" */ (0) << 1
+       _ = float64 /* ERROR "must be integer" */ (0) >> 2
+       _ = complex64 /* ERROR "must be integer" */ (0) << 3
+       _ = complex64 /* ERROR "must be integer" */ (0) >> 4
+}
+
+func issue21727() {
+       var s uint
+       var a = make([]int, 1<<s + 1.2 /* ERROR "truncated to int" */ )
+       var _ = a[1<<s - 2.3 /* ERROR "truncated to int" */ ]
+       var _ int = 1<<s + 3.4 /* ERROR "truncated to int" */
+       var _ = string(1 << s)
+       var _ = string(1.0 /* ERROR "cannot convert" */ << s)
+}
+
+func issue22969() {
+       var s uint
+       var a []byte
+       _ = a[0xffffffffffffffff /* ERROR "overflows int" */ <<s] // example from issue 22969
+       _ = make([]int, 0xffffffffffffffff /* ERROR "overflows int" */ << s)
+       _ = make([]int, 0, 0xffffffffffffffff /* ERROR "overflows int" */ << s)
+       var _ byte = 0x100 /* ERROR "overflows byte" */ << s
+       var _ int8 = 0xff /* ERROR "overflows int8" */ << s
+       var _ int16 = 0xffff /* ERROR "overflows int16" */ << s
+       var _ int32 = 0x80000000 /* ERROR "overflows int32" */ << s
+}
diff --git a/src/cmd/compile/internal/types2/testdata/slices.go2 b/src/cmd/compile/internal/types2/testdata/slices.go2
new file mode 100644 (file)
index 0000000..2bacd1c
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2019 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 slices implements various slice algorithms.
+package slices
+
+// Map turns a []T1 to a []T2 using a mapping function.
+func Map[T1, T2 any](s []T1, f func(T1) T2) []T2 {
+       r := make([]T2, len(s))
+       for i, v := range s {
+               r[i] = f(v)
+       }
+       return r
+}
+
+// Reduce reduces a []T1 to a single value using a reduction function.
+func Reduce[T1, T2 any](s []T1, initializer T2, f func(T2, T1) T2) T2 {
+       r := initializer
+       for _, v := range s {
+               r = f(r, v)
+       }
+       return r
+}
+
+// Filter filters values from a slice using a filter function.
+func Filter[T any](s []T, f func(T) bool) []T {
+       var r []T
+       for _, v := range s {
+               if f(v) {
+                       r = append(r, v)
+               }
+       }
+       return r
+}
+
+// Example uses
+
+func limiter(x int) byte {
+       switch {
+       case x < 0:
+               return 0
+       default:
+               return byte(x)
+       case x > 255:
+               return 255
+       }
+}
+
+var input = []int{-4, 68954, 7, 44, 0, -555, 6945}
+var limited1 = Map[int, byte](input, limiter)
+var limited2 = Map(input, limiter) // using type inference
+
+func reducer(x float64, y int) float64 {
+       return x + float64(y)
+}
+
+var reduced1 = Reduce[int, float64](input, 0, reducer)
+var reduced2 = Reduce(input, 1i /* ERROR overflows */, reducer) // using type inference
+var reduced3 = Reduce(input, 1, reducer) // using type inference
+
+func filter(x int) bool {
+       return x&1 != 0
+}
+
+var filtered1 = Filter[int](input, filter)
+var filtered2 = Filter(input, filter) // using type inference
+
diff --git a/src/cmd/compile/internal/types2/testdata/stmt0.src b/src/cmd/compile/internal/types2/testdata/stmt0.src
new file mode 100644 (file)
index 0000000..959f7d5
--- /dev/null
@@ -0,0 +1,980 @@
+// Copyright 2012 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.
+
+// statements
+
+package stmt0
+
+func assignments0() (int, int) {
+       var a, b, c int
+       var ch chan int
+       f0 := func() {}
+       f1 := func() int { return 1 }
+       f2 := func() (int, int) { return 1, 2 }
+       f3 := func() (int, int, int) { return 1, 2, 3 }
+
+       a, b, c = 1, 2, 3
+       a, b, c = 1 /* ERROR "cannot assign [1-9]+ values to [1-9]+ variables" */ , 2
+       a, b, c = 1 /* ERROR "cannot assign [1-9]+ values to [1-9]+ variables" */ , 2, 3, 4
+       _, _, _ = a, b, c
+
+       a = f0 /* ERROR "used as value" */ ()
+       a = f1()
+       a = f2 /* ERROR "cannot assign [1-9]+ values to [1-9]+ variables" */ ()
+       a, b = f2()
+       a, b, c = f2 /* ERROR "cannot assign [1-9]+ values to [1-9]+ variables" */ ()
+       a, b, c = f3()
+       a, b = f3 /* ERROR "cannot assign [1-9]+ values to [1-9]+ variables" */ ()
+
+       a, b, c = <- /* ERROR "cannot assign [1-9]+ values to [1-9]+ variables" */ ch
+
+       return /* ERROR "wrong number of return values" */
+       return /* ERROR "wrong number of return values" */ 1
+       return 1, 2
+       return /* ERROR "wrong number of return values" */ 1, 2, 3
+}
+
+func assignments1() {
+       b, i, f, c, s := false, 1, 1.0, 1i, "foo"
+       b = i /* ERROR "cannot use .* in assignment" */
+       i = f /* ERROR "cannot use .* in assignment" */
+       f = c /* ERROR "cannot use .* in assignment" */
+       c = s /* ERROR "cannot use .* in assignment" */
+       s = b /* ERROR "cannot use .* in assignment" */
+
+       v0, v1, v2 := 1 /* ERROR "cannot initialize" */ , 2, 3, 4
+       _, _, _ = v0, v1, v2
+
+       b = true
+
+       i += 1
+       i += "foo" /* ERROR "cannot convert.*int" */
+
+       f -= 1
+       f /= 0
+       f = float32(0)/0 /* ERROR "division by zero" */
+       f -= "foo" /* ERROR "cannot convert.*float64" */
+
+       c *= 1
+       c /= 0
+
+       s += "bar"
+       s += 1 /* ERROR "cannot convert.*string" */
+
+       var u64 uint64
+       u64 += 1<<u64
+
+       undeclared /* ERROR "undeclared" */ = 991
+
+       // test cases for issue 5800
+       var (
+               _ int = nil /* ERROR "untyped nil value" */
+               _ [10]int = nil /* ERROR "untyped nil value" */
+               _ []byte = nil
+               _ struct{} = nil /* ERROR "untyped nil value" */
+               _ func() = nil
+               _ map[int]string = nil
+               _ chan int = nil
+       )
+
+       // test cases for issue 5500
+       _ = func() (int, bool) {
+               var m map[int]int
+               return /* ERROR "wrong number of return values" */ m[0]
+       }
+
+       g := func(int, bool){}
+       var m map[int]int
+       g(m[0]) /* ERROR "not enough arguments" */
+
+       // assignments to _
+       _ = nil /* ERROR "use of untyped nil" */
+       _ = 1 /* ERROR overflow */ <<1000
+       (_) = 0
+}
+
+func assignments2() {
+       type mybool bool
+       var m map[string][]bool
+       var s []bool
+       var b bool
+       var d mybool
+       _ = s
+       _ = b
+       _ = d
+
+       // assignments to map index expressions are ok
+       s, b = m["foo"]
+       _, d = m["bar"]
+       m["foo"] = nil
+       m["foo"] = nil /* ERROR cannot assign [1-9]+ values to [1-9]+ variables */ , false
+       _ = append(m["foo"])
+       _ = append(m["foo"], true)
+
+       var c chan int
+       _, b = <-c
+       _, d = <-c
+       <- /* ERROR cannot assign */ c = 0
+       <-c = 0 /* ERROR cannot assign [1-9]+ values to [1-9]+ variables */ , false
+
+       var x interface{}
+       _, b = x.(int)
+       x /* ERROR cannot assign */ .(int) = 0
+       x.(int) = 0 /* ERROR cannot assign [1-9]+ values to [1-9]+ variables */ , false
+
+       assignments2 /* ERROR used as value */ () = nil
+       int /* ERROR not an expression */ = 0
+}
+
+func issue6487() {
+       type S struct{x int}
+       _ = &S /* ERROR "cannot take address" */ {}.x
+       _ = &( /* ERROR "cannot take address" */ S{}.x)
+       _ = (&S{}).x
+       S /* ERROR "cannot assign" */ {}.x = 0
+       (&S{}).x = 0
+
+       type M map[string]S
+       var m M
+       m /* ERROR "cannot assign to struct field" */ ["foo"].x = 0
+       _ = &( /* ERROR "cannot take address" */ m["foo"].x)
+       _ = &m /* ERROR "cannot take address" */ ["foo"].x
+}
+
+func issue6766a() {
+       a, a /* ERROR redeclared */ := 1, 2
+       _ = a
+       a, b, b /* ERROR redeclared */ := 1, 2, 3
+       _ = b
+       c, c /* ERROR redeclared */, b := 1, 2, 3
+       _ = c
+       a, b := /* ERROR no new variables */ 1, 2
+}
+
+func shortVarDecls1() {
+       const c = 0
+       type d int
+       a, b, c /* ERROR "cannot assign" */ , d /* ERROR "cannot assign" */  := 1, "zwei", 3.0, 4
+       var _ int = a // a is of type int
+       var _ string = b // b is of type string
+}
+
+func incdecs() {
+       const c = 3.14
+       c /* ERROR "cannot assign" */ ++
+       s := "foo"
+       s /* ERROR "invalid operation" */ --
+       3.14 /* ERROR "cannot assign" */ ++
+       var (
+               x int
+               y float32
+               z complex128
+       )
+       x++
+       y--
+       z++
+}
+
+func sends() {
+       var ch chan int
+       var rch <-chan int
+       var x int
+       x <- /* ERROR "cannot send" */ x
+       rch <- /* ERROR "cannot send" */ x
+       ch <- "foo" /* ERROR "cannot convert" */
+       ch <- x
+}
+
+func selects() {
+       select {}
+       var (
+               ch chan int
+               sc chan <- bool
+       )
+       select {
+       case <-ch:
+       case (<-ch):
+       case t := <-ch:
+               _ = t
+       case t := (<-ch):
+               _ = t
+       case t, ok := <-ch:
+               _, _ = t, ok
+       case t, ok := (<-ch):
+               _, _ = t, ok
+       case <-sc /* ERROR "cannot receive from send-only channel" */ :
+       }
+       select {
+       default:
+       default /* ERROR "multiple defaults" */ :
+       }
+       select {
+       case a, b := <-ch:
+               _, b = a, b
+       case x /* ERROR send or receive */ :
+       case a /* ERROR send or receive */ := ch:
+       }
+
+       // test for issue 9570: ch2 in second case falsely resolved to
+       // ch2 declared in body of first case
+       ch1 := make(chan int)
+       ch2 := make(chan int)
+       select {
+       case <-ch1:
+               var ch2 /* ERROR ch2 declared but not used */ chan bool
+       case i := <-ch2:
+               print(i + 1)
+       }
+}
+
+func gos() {
+       go 1 /* ERROR must be function call */ /* ERROR cannot call non-function */
+       go int /* ERROR "go requires function call, not conversion" */ (0)
+       go gos()
+       var c chan int
+       go close(c)
+       go len /* ERROR "go discards result" */ (c)
+}
+
+func defers() {
+       defer 1 /* ERROR must be function call */ /* ERROR cannot call non-function */
+       defer int /* ERROR "defer requires function call, not conversion" */ (0)
+       defer defers()
+       var c chan int
+       defer close(c)
+       defer len /* ERROR "defer discards result" */ (c)
+}
+
+func breaks() {
+       var x, y int
+
+       break /* ERROR "break" */
+       {
+               break /* ERROR "break" */
+       }
+       if x < y {
+               break /* ERROR "break" */
+       }
+
+       switch x {
+       case 0:
+               break
+       case 1:
+               if x == y {
+                       break
+               }
+       default:
+               break
+               break
+       }
+
+       var z interface{}
+       switch z.(type) {
+       case int:
+               break
+       }
+
+       for {
+               break
+       }
+
+       var a []int
+       for _ = range a {
+               break
+       }
+
+       for {
+               if x == y {
+                       break
+               }
+       }
+
+       var ch chan int
+       select {
+       case <-ch:
+               break
+       }
+
+       select {
+       case <-ch:
+               if x == y {
+                       break
+               }
+       default:
+               break
+       }
+}
+
+func continues() {
+       var x, y int
+
+       continue /* ERROR "continue" */
+       {
+               continue /* ERROR "continue" */
+       }
+
+       if x < y {
+               continue /* ERROR "continue" */
+       }
+
+       switch x {
+       case 0:
+               continue /* ERROR "continue" */
+       }
+
+       var z interface{}
+       switch z.(type) {
+       case int:
+               continue /* ERROR "continue" */
+       }
+
+       var ch chan int
+       select {
+       case <-ch:
+               continue /* ERROR "continue" */
+       }
+
+       for i := 0; i < 10; i++ {
+               continue
+               if x < y {
+                       continue
+                       break
+               }
+               switch x {
+               case y:
+                       continue
+               default:
+                       break
+               }
+               select {
+               case <-ch:
+                       continue
+               }
+       }
+
+       var a []int
+       for _ = range a {
+               continue
+               if x < y {
+                       continue
+                       break
+               }
+               switch x {
+               case y:
+                       continue
+               default:
+                       break
+               }
+               select {
+               case <-ch:
+                       continue
+               }
+       }
+}
+
+func returns0() {
+       return
+       return 0 /* ERROR no result values expected */
+}
+
+func returns1(x float64) (int, *float64) {
+       return 0, &x
+       return /* ERROR wrong number of return values */
+       return "foo" /* ERROR "cannot convert" */, x /* ERROR "cannot use .* in return statement" */
+       return /* ERROR wrong number of return values */ 0, &x, 1
+}
+
+func returns2() (a, b int) {
+       return
+       return 1, "foo" /* ERROR cannot convert */
+       return /* ERROR wrong number of return values */ 1, 2, 3
+       {
+               type a int
+               return 1, 2
+               return /* ERROR a not in scope at return */
+       }
+}
+
+func returns3() (_ int) {
+       return
+       {
+               var _ int // blank (_) identifiers never shadow since they are in no scope
+               return
+       }
+}
+
+func switches0() {
+       var x int
+
+       switch x {
+       }
+
+       switch x {
+       default:
+       default /* ERROR "multiple defaults" */ :
+       }
+
+       switch {
+       case 1  /* ERROR "cannot convert" */ :
+       }
+
+       true := "false"
+       _ = true
+       // A tagless switch is equivalent to the bool
+        // constant true, not the identifier 'true'.
+       switch {
+       case "false" /* ERROR "cannot convert" */:
+       }
+
+       switch int32(x) {
+       case 1, 2:
+       case x /* ERROR "cannot compare" */ :
+       }
+
+       switch x {
+       case 1 /* ERROR "overflows" */ << 100:
+       }
+
+       switch x {
+       case 1:
+       case 1 /* ERROR "duplicate case" */ :
+       case ( /* ERROR "duplicate case" */ 1):
+       case 2, 3, 4:
+       case 5, 1 /* ERROR "duplicate case" */ :
+       }
+
+       switch uint64(x) {
+       case 1<<64 - 1:
+       case 1 /* ERROR duplicate case */ <<64 - 1:
+       case 2, 3, 4:
+       case 5, 1 /* ERROR duplicate case */ <<64 - 1:
+       }
+
+       var y32 float32
+       switch y32 {
+       case 1.1:
+       case 11/10: // integer division!
+       case 11. /* ERROR duplicate case */ /10:
+       case 2, 3.0, 4.1:
+       case 5.2, 1.10 /* ERROR duplicate case */ :
+       }
+
+       var y64 float64
+       switch y64 {
+       case 1.1:
+       case 11/10: // integer division!
+       case 11. /* ERROR duplicate case */ /10:
+       case 2, 3.0, 4.1:
+       case 5.2, 1.10 /* ERROR duplicate case */ :
+       }
+
+       var s string
+       switch s {
+       case "foo":
+       case "foo" /* ERROR duplicate case */ :
+       case "f" /* ERROR duplicate case */ + "oo":
+       case "abc", "def", "ghi":
+       case "jkl", "foo" /* ERROR duplicate case */ :
+       }
+
+       type T int
+       type F float64
+       type S string
+       type B bool
+       var i interface{}
+       switch i {
+       case nil:
+       case nil: // no duplicate detection
+       case (*int)(nil):
+       case (*int)(nil): // do duplicate detection
+       case 1:
+       case byte(1):
+       case int /* ERROR duplicate case */ (1):
+       case T(1):
+       case 1.0:
+       case F(1.0):
+       case F /* ERROR duplicate case */ (1.0):
+       case "hello":
+       case S("hello"):
+       case S /* ERROR duplicate case */ ("hello"):
+       case 1==1, B(false):
+       case false, B(2==2):
+       }
+
+       // switch on array
+       var a [3]int
+       switch a {
+       case [3]int{1, 2, 3}:
+       case [3]int{1, 2, 3}: // no duplicate detection
+       case [ /* ERROR "mismatched types */ 4]int{4, 5, 6}:
+       }
+
+       // switch on channel
+       var c1, c2 chan int
+       switch c1 {
+       case nil:
+       case c1:
+       case c2:
+       case c1, c2: // no duplicate detection
+       }
+}
+
+func switches1() {
+       fallthrough /* ERROR "fallthrough statement out of place" */
+
+       var x int
+       switch x {
+       case 0:
+               fallthrough /* ERROR "fallthrough statement out of place" */
+               break
+       case 1:
+               fallthrough
+       case 2:
+               fallthrough; ; ; // trailing empty statements are ok
+       case 3:
+       default:
+               fallthrough; ;
+       case 4:
+               fallthrough /* ERROR "cannot fallthrough final case in switch" */
+       }
+
+       var y interface{}
+       switch y.(type) {
+       case int:
+               fallthrough /* ERROR "fallthrough statement out of place" */ ; ; ;
+       default:
+       }
+
+       switch x {
+       case 0:
+               if x == 0 {
+                       fallthrough /* ERROR "fallthrough statement out of place" */
+               }
+       }
+
+       switch x {
+       case 0:
+               goto L1
+               L1: fallthrough; ;
+       case 1:
+               goto L2
+               goto L3
+               goto L4
+               L2: L3: L4: fallthrough
+       default:
+       }
+
+       switch x {
+       case 0:
+               goto L5
+               L5: fallthrough
+       default:
+               goto L6
+               goto L7
+               goto L8
+               L6: L7: L8: fallthrough /* ERROR "cannot fallthrough final case in switch" */
+       }
+
+       switch x {
+       case 0:
+               fallthrough; ;
+       case 1:
+               {
+                       fallthrough /* ERROR "fallthrough statement out of place" */
+               }
+       case 2:
+               fallthrough
+       case 3:
+               fallthrough /* ERROR "fallthrough statement out of place" */
+               { /* empty block is not an empty statement */ }; ;
+       default:
+               fallthrough /* ERROR "cannot fallthrough final case in switch" */
+       }
+
+       switch x {
+       case 0:
+               {
+                       fallthrough /* ERROR "fallthrough statement out of place" */
+               }
+       }
+}
+
+func switches2() {
+       // untyped nil is not permitted as switch expression
+       switch nil /* ERROR "use of untyped nil" */ {
+       case 1, 2, "foo": // don't report additional errors here
+       }
+
+       // untyped constants are converted to default types
+       switch 1<<63-1 {
+       }
+       switch 1 /* ERROR "overflows int" */ << 63 {
+       }
+       var x int
+       switch 1.0 {
+       case 1.0, 2.0, x /* ERROR "mismatched types int and float64" */ :
+       }
+       switch x {
+       case 1.0:
+       }
+
+       // untyped bools become of type bool
+       type B bool
+       var b B = true
+       switch x == x {
+       case b /* ERROR "mismatched types B and bool" */ :
+       }
+       switch {
+       case b /* ERROR "mismatched types B and bool" */ :
+       }
+}
+
+func issue11667() {
+       switch 9223372036854775808 /* ERROR "overflows int" */ {
+       }
+       switch 9223372036854775808 /* ERROR "overflows int" */ {
+       case 9223372036854775808:
+       }
+       var x int
+       switch x {
+       case 9223372036854775808 /* ERROR "overflows int" */ :
+       }
+       var y float64
+       switch y {
+       case 9223372036854775808:
+       }
+}
+
+func issue11687() {
+       f := func() (_, _ int) { return }
+       switch f /* ERROR "2-valued f" */ () {
+       }
+       var x int
+       switch f /* ERROR "2-valued f" */ () {
+       case x:
+       }
+       switch x {
+       case f /* ERROR "2-valued f" */ ():
+       }
+}
+
+type I interface {
+       m()
+}
+
+type I2 interface {
+       m(int)
+}
+
+type T struct{}
+type T1 struct{}
+type T2 struct{}
+
+func (T) m() {}
+func (T2) m(int) {}
+
+func typeswitches() {
+       var i int
+       var x interface{}
+
+       switch x.(type) {}
+       switch (x /* ERROR "outside type switch" */ .(type)) {}
+
+       switch x.(type) {
+       default:
+       default /* ERROR "multiple defaults" */ :
+       }
+
+       switch x /* ERROR "declared but not used" */ := x.(type) {}
+       switch _ /* ERROR "no new variable on left side of :=" */ := x.(type) {}
+
+       switch x := x.(type) {
+       case int:
+               var y int = x
+               _ = y
+       }
+
+       switch x := i /* ERROR "not an interface" */ .(type) {}
+
+       switch t := x.(type) {
+       case nil:
+               var v bool = t /* ERROR "cannot use .* in variable declaration" */
+               _ = v
+       case int:
+               var v int = t
+               _ = v
+       case float32, complex64:
+               var v float32 = t /* ERROR "cannot use .* in variable declaration" */
+               _ = v
+       default:
+               var v float32 = t /* ERROR "cannot use .* in variable declaration" */
+               _ = v
+       }
+
+       var t I
+       switch t.(type) {
+       case T:
+       case T1 /* ERROR "missing method m" */ :
+       case T2 /* ERROR "wrong type for method m" */ :
+       case I2 /* STRICT "wrong type for method m" */ : // only an error in strict mode (issue 8561)
+       }
+}
+
+// Test that each case clause uses the correct type of the variable
+// declared by the type switch (issue 5504).
+func typeswitch0() {
+       switch y := interface{}(nil).(type) {
+       case int:
+               func() int { return y + 0 }()
+       case float32:
+               func() float32 { return y }()
+       }
+}
+
+// Test correct scope setup.
+// (no redeclaration errors expected in the type switch)
+func typeswitch1() {
+       var t I
+       switch t := t; t := t.(type) {
+       case nil:
+               var _ I = t
+       case T:
+               var _ T = t
+       default:
+               var _ I = t
+       }
+}
+
+// Test correct typeswitch against interface types.
+type A interface { a() }
+type B interface { b() }
+type C interface { a(int) }
+
+func typeswitch2() {
+       switch A(nil).(type) {
+       case A:
+       case B:
+       case C /* STRICT "cannot have dynamic type" */: // only an error in strict mode (issue 8561)
+       }
+}
+
+func typeswitch3(x interface{}) {
+       switch x.(type) {
+       case int:
+       case float64:
+       case int /* ERROR duplicate case */ :
+       }
+
+       switch x.(type) {
+       case nil:
+       case int:
+       case nil /* ERROR duplicate case */ , nil /* ERROR duplicate case */ :
+       }
+
+       type F func(int)
+       switch x.(type) {
+       case nil:
+       case int, func(int):
+       case float32, func /* ERROR duplicate case */ (x int):
+       case F:
+       }
+}
+
+func fors1() {
+       for {}
+       var i string
+       _ = i
+       for i := 0; i < 10; i++ {}
+       for i := 0; i < 10; j /* ERROR cannot declare */ := 0 {}
+}
+
+func rangeloops1() {
+       var (
+               x int
+               a [10]float32
+               b []string
+               p *[10]complex128
+               pp **[10]complex128
+               s string
+               m map[int]bool
+               c chan int
+               sc chan<- int
+               rc <-chan int
+       )
+
+       for range x /* ERROR "cannot range over" */ {}
+       for _ = range x /* ERROR "cannot range over" */ {}
+       for i := range x /* ERROR "cannot range over" */ {}
+
+       for range a {}
+       for i := range a {
+               var ii int
+               ii = i
+               _ = ii
+       }
+       for i, x := range a {
+               var ii int
+               ii = i
+               _ = ii
+               var xx float64
+               xx = x /* ERROR "cannot use .* in assignment" */
+               _ = xx
+       }
+       var ii int
+       var xx float32
+       for ii, xx = range a {}
+       _, _ = ii, xx
+
+       for range b {}
+       for i := range b {
+               var ii int
+               ii = i
+               _ = ii
+       }
+       for i, x := range b {
+               var ii int
+               ii = i
+               _ = ii
+               var xx string
+               xx = x
+               _ = xx
+       }
+
+       for range s {}
+       for i := range s {
+               var ii int
+               ii = i
+               _ = ii
+       }
+       for i, x := range s {
+               var ii int
+               ii = i
+               _ = ii
+               var xx rune
+               xx = x
+               _ = xx
+       }
+
+       for range p {}
+       for _, x := range p {
+               var xx complex128
+               xx = x
+               _ = xx
+       }
+
+       for range pp /* ERROR "cannot range over" */ {}
+       for _, x := range pp /* ERROR "cannot range over" */ {}
+
+       for range m {}
+       for k := range m {
+               var kk int32
+               kk = k /* ERROR "cannot use .* in assignment" */
+               _ = kk
+       }
+       for k, v := range m {
+               var kk int
+               kk = k
+               _ = kk
+               if v {}
+       }
+
+       for range c {}
+       for _, _ /* ERROR "only one iteration variable" */ = range c {}
+       for e := range c {
+               var ee int
+               ee = e
+               _ = ee
+       }
+       for _ = range sc /* ERROR "send-only channel" */ {}
+       for _ = range rc {}
+
+       // constant strings
+       const cs = "foo"
+       for range cs {}
+       for range "" {}
+       for i, x := range cs { _, _ = i, x }
+       for i, x := range "" {
+               var ii int
+               ii = i
+               _ = ii
+               var xx rune
+               xx = x
+               _ = xx
+       }
+}
+
+func rangeloops2() {
+       type I int
+       type R rune
+
+       var a [10]int
+       var i I
+       _ = i
+       for i /* ERROR cannot use .* in assignment */ = range a {}
+       for i /* ERROR cannot use .* in assignment */ = range &a {}
+       for i /* ERROR cannot use .* in assignment */ = range a[:] {}
+
+       var s string
+       var r R
+       _ = r
+       for i /* ERROR cannot use .* in assignment */ = range s {}
+       for i /* ERROR cannot use .* in assignment */ = range "foo" {}
+       for _, r /* ERROR cannot use .* in assignment */ = range s {}
+       for _, r /* ERROR cannot use .* in assignment */ = range "foo" {}
+}
+
+func issue6766b() {
+       for _ := /* ERROR no new variables */ range "" {}
+       for a, a /* ERROR redeclared */ := range "" { _ = a }
+       var a int
+       _ = a
+       for a, a /* ERROR redeclared */ := range []int{1, 2, 3} { _ = a }
+}
+
+// Test that despite errors in the range clause,
+// the loop body is still type-checked (and thus
+// errors reported).
+func issue10148() {
+       for y /* ERROR declared but not used */ := range "" {
+               _ = "" /* ERROR cannot convert */ + 1
+       }
+       for range 1 /* ERROR cannot range over 1 */ {
+               _ = "" /* ERROR cannot convert */ + 1
+       }
+       for y := range 1 /* ERROR cannot range over 1 */ {
+               _ = "" /* ERROR cannot convert */ + 1
+       }
+}
+
+func labels0() {
+       goto L0
+       goto L1
+       L0:
+       L1:
+       L1 /* ERROR "already declared" */ :
+       if true {
+               goto L2
+               L2:
+               L0 /* ERROR "already declared" */ :
+       }
+       _ = func() {
+               goto L0
+               goto L1
+               goto L2
+               L0:
+               L1:
+               L2:
+       }
+}
+
+func expression_statements(ch chan int) {
+       expression_statements(ch)
+       <-ch
+       println()
+
+       0 /* ERROR "not used" */
+       1 /* ERROR "not used" */ +2
+       cap /* ERROR "not used" */ (ch)
+       println /* ERROR "must be called" */
+}
diff --git a/src/cmd/compile/internal/types2/testdata/stmt1.src b/src/cmd/compile/internal/types2/testdata/stmt1.src
new file mode 100644 (file)
index 0000000..f79f920
--- /dev/null
@@ -0,0 +1,259 @@
+// Copyright 2013 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.
+
+// terminating statements
+
+package stmt1
+
+func _() {}
+
+func _() int {} /* ERROR "missing return" */
+
+func _() int { panic(0) }
+func _() int { (panic(0)) }
+
+// block statements
+func _(x, y int) (z int) {
+       {
+               return
+       }
+}
+
+func _(x, y int) (z int) {
+       {
+               return; ; ; // trailing empty statements are ok
+       }
+       ; ; ;
+}
+
+func _(x, y int) (z int) {
+       {
+       }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+       {
+               ; ; ;
+       }
+       ; ; ;
+} /* ERROR "missing return" */
+
+// if statements
+func _(x, y int) (z int) {
+       if x < y { return }
+       return 1
+}
+
+func _(x, y int) (z int) {
+       if x < y { return; ; ; ; }
+       return 1
+}
+
+func _(x, y int) (z int) {
+       if x < y { return }
+       return 1; ;
+}
+
+func _(x, y int) (z int) {
+       if x < y { return }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+       if x < y {
+       } else { return 1
+       }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+       if x < y { return
+       } else { return
+       }
+}
+
+// for statements
+func _(x, y int) (z int) {
+       for x < y {
+               return
+       }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+       for {
+               return
+       }
+}
+
+func _(x, y int) (z int) {
+       for {
+               return; ; ; ;
+       }
+}
+
+func _(x, y int) (z int) {
+       for {
+               return
+               break
+       }
+       ; ; ;
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+       for {
+               for { break }
+               return
+       }
+}
+
+func _(x, y int) (z int) {
+       for {
+               for { break }
+               return ; ;
+       }
+       ;
+}
+
+func _(x, y int) (z int) {
+L:     for {
+               for { break L }
+               return
+       }
+} /* ERROR "missing return" */
+
+// switch statements
+func _(x, y int) (z int) {
+       switch x {
+       case 0: return
+       default: return
+       }
+}
+
+func _(x, y int) (z int) {
+       switch x {
+       case 0: return;
+       default: return; ; ;
+       }
+}
+
+func _(x, y int) (z int) {
+       switch x {
+       case 0: return
+       }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+       switch x {
+       case 0: return
+       case 1: break
+       }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+       switch x {
+       case 0: return
+       default:
+               switch y {
+               case 0: break
+               }
+               panic(0)
+       }
+}
+
+func _(x, y int) (z int) {
+       switch x {
+       case 0: return
+       default:
+               switch y {
+               case 0: break
+               }
+               panic(0); ; ;
+       }
+       ;
+}
+
+func _(x, y int) (z int) {
+L:     switch x {
+       case 0: return
+       default:
+               switch y {
+               case 0: break L
+               }
+               panic(0)
+       }
+} /* ERROR "missing return" */
+
+// select statements
+func _(ch chan int) (z int) {
+       select {}
+} // nice!
+
+func _(ch chan int) (z int) {
+       select {}
+       ; ;
+}
+
+func _(ch chan int) (z int) {
+       select {
+       default: break
+       }
+} /* ERROR "missing return" */
+
+func _(ch chan int) (z int) {
+       select {
+       case <-ch: return
+       default: break
+       }
+} /* ERROR "missing return" */
+
+func _(ch chan int) (z int) {
+       select {
+       case <-ch: return
+       default:
+               for i := 0; i < 10; i++ {
+                       break
+               }
+               return
+       }
+}
+
+func _(ch chan int) (z int) {
+       select {
+       case <-ch: return; ; ;
+       default:
+               for i := 0; i < 10; i++ {
+                       break
+               }
+               return; ; ;
+       }
+       ; ; ;
+}
+
+func _(ch chan int) (z int) {
+L:     select {
+       case <-ch: return
+       default:
+               for i := 0; i < 10; i++ {
+                       break L
+               }
+               return
+       }
+       ; ; ;
+} /* ERROR "missing return" */
+
+func parenPanic() int {
+       ((((((panic)))(0))))
+}
+
+func issue23218a() int {
+       {
+               panic := func(interface{}){}
+               panic(0)
+       }
+} /* ERROR "missing return" */
+
+func issue23218b() int {
+       {
+               panic := func(interface{}){}
+               ((((panic))))(0)
+       }
+} /* ERROR "missing return" */
diff --git a/src/cmd/compile/internal/types2/testdata/tinference.go2 b/src/cmd/compile/internal/types2/testdata/tinference.go2
new file mode 100644 (file)
index 0000000..a53fde0
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright 2020 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 tinferenceB
+
+import "strconv"
+
+type any interface{}
+
+func f0[A any, B interface{type C}, C interface{type D}, D interface{type A}](A, B, C, D)
+func _() {
+       f := f0[string]
+       f("a", "b", "c", "d")
+       f0("a", "b", "c", "d")
+}
+
+func f1[A any, B interface{type A}](A, B)
+func _() {
+       f := f1[int]
+       f(int(0), int(0))
+       f1(int(0), int(0))
+}
+
+func f2[A any, B interface{type []A}](A, B)
+func _() {
+       f := f2[byte]
+       f(byte(0), []byte{})
+       f2(byte(0), []byte{})
+}
+
+func f3[A any, B interface{type C}, C interface{type *A}](A, B, C)
+func _() {
+       f := f3[int]
+       var x int
+       f(x, &x, &x)
+       f3(x, &x, &x)
+}
+
+func f4[A any, B interface{type []C}, C interface{type *A}](A, B, C)
+func _() {
+       f := f4[int]
+       var x int
+       f(x, []*int{}, &x)
+       f4(x, []*int{}, &x)
+}
+
+func f5[A interface{type struct{b B; c C}}, B any, C interface{type *B}](x B) A
+func _() {
+       x := f5(1.2)
+       var _ float64 = x.b
+       var _ float64 = *x.c
+}
+
+func f6[A any, B interface{type struct{f []A}}](B) A
+func _() {
+       x := f6(struct{f []string}{})
+       var _ string = x
+}
+
+// TODO(gri) Need to flag invalid recursive constraints. At the
+// moment these cause infinite recursions and stack overflow.
+// func f7[A interface{type B}, B interface{type A}]()
+
+// More realistic examples
+
+func Double[S interface{ type []E }, E interface{ type int, int8, int16, int32, int64 }](s S) S {
+       r := make(S, len(s))
+       for i, v := range s {
+               r[i] = v + v
+       }
+       return r
+}
+
+type MySlice []int
+
+var _ = Double(MySlice{1})
+
+// From the draft design.
+
+type Setter[B any] interface {
+       Set(string)
+       type *B
+}
+
+func FromStrings[T interface{}, PT Setter[T]](s []string) []T {
+       result := make([]T, len(s))
+       for i, v := range s {
+               // The type of &result[i] is *T which is in the type list
+               // of Setter2, so we can convert it to PT.
+               p := PT(&result[i])
+               // PT has a Set method.
+               p.Set(v)
+       }
+       return result
+}
+
+type Settable int
+
+func (p *Settable) Set(s string) {
+       i, _ := strconv.Atoi(s) // real code should not ignore the error
+       *p = Settable(i)
+}
+
+var _ = FromStrings[Settable]([]string{"1", "2"})
diff --git a/src/cmd/compile/internal/types2/testdata/tmp.go2 b/src/cmd/compile/internal/types2/testdata/tmp.go2
new file mode 100644 (file)
index 0000000..dae78ca
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2020 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.
+
+// This file is meant as "dumping ground" for debugging code.
+
+package p
+
+// fun test case
+type C[P interface{m()}] P
+
+func (r C[P]) m() { r.m() }
+
+func f[T interface{m(); n()}](x T) {
+       y := C[T](x)
+       y.m()
+}
diff --git a/src/cmd/compile/internal/types2/testdata/typeinst.go2 b/src/cmd/compile/internal/types2/testdata/typeinst.go2
new file mode 100644 (file)
index 0000000..6757cd5
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2019 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 myInt int
+
+// Parameterized type declarations
+
+type T1[P any] P
+
+type T2[P any] struct {
+        f P
+        g int // int should still be in scope chain
+}
+
+type List[P any] []P
+
+// Alias type declarations cannot have type parameters. Syntax error.
+type A1[P any] = /* ERROR cannot be alias */ P
+
+// But an alias may refer to a generic, uninstantiated type.
+type A2 = List
+var _ A2[int]
+var _ A2 /* ERROR without instantiation */
+
+type A3 = List[int]
+var _ A3
+
+// Parameterized type instantiations
+
+var x int
+type _ x /* ERROR not a type */ [int]
+
+type _ int[] // ERROR expecting type
+type _ myInt[] // ERROR expecting type
+
+// TODO(gri) better error messages
+type _ T1 /* ERROR without instantiation */ [] // ERROR expecting type
+type _ T1[x /* ERROR not a type */ ]
+type _ T1 /* ERROR got 2 arguments but 1 type parameters */ [int, float32]
+
+var _ T2[int] = T2[int]{}
+
+var _ List[int] = []int{1, 2, 3}
+var _ List[[]int] = [][]int{{1, 2, 3}}
+var _ List[List[List[int]]]
+
+// Parameterized types containing parameterized types
+
+type T3[P any] List[P]
+
+var _ T3[int] = T3[int](List[int]{1, 2, 3})
+
+// Self-recursive generic types are not permitted
+
+type self1[P any] self1 /* ERROR illegal cycle */ [P]
+type self2[P any] *self2[P] // this is ok
diff --git a/src/cmd/compile/internal/types2/testdata/typeinst2.go2 b/src/cmd/compile/internal/types2/testdata/typeinst2.go2
new file mode 100644 (file)
index 0000000..6e2104a
--- /dev/null
@@ -0,0 +1,256 @@
+// Copyright 2019 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 List[E any] []E
+var _ List[List[List[int]]]
+var _ List[List[List[int]]] = []List[List[int]]{}
+
+type (
+       T1[P1 any] struct {
+               f1 T2[P1, float32]
+       }
+
+       T2[P2, P3 any] struct {
+               f2 P2
+               f3 P3
+       }
+)
+
+func _() {
+       var x1 T1[int]
+       var x2 T2[int, float32]
+
+       x1.f1.f2 = 0
+       x1.f1 = x2
+}
+
+type T3[P any] T1[T2[P, P]]
+
+func _() {
+       var x1 T3[int]
+       var x2 T2[int, int]
+       x1.f1.f2 = x2
+}
+
+func f[P any] (x P) List[P] {
+       return List[P]{x}
+}
+
+var (
+       _ []int = f(0)
+       _ []float32 = f[float32](10)
+       _ List[complex128] = f(1i)
+       _ []List[int] = f(List[int]{})
+        _ List[List[int]] = []List[int]{}
+        _ = []List[int]{}
+)
+
+// Parameterized types with methods
+
+func (l List[E]) Head() (_ E, _ bool) {
+       if len(l) > 0 {
+               return l[0], true
+       }
+       return
+}
+
+// A test case for instantiating types with other types (extracted from map.go2)
+
+type Pair[K any] struct {
+       key K
+}
+
+type Receiver[T any] struct {
+       values T
+}
+
+type Iterator[K any] struct {
+       r Receiver[Pair[K]]
+}
+
+func Values [T any] (r Receiver[T]) T {
+        return r.values
+}
+
+func (it Iterator[K]) Next() K {
+        return Values[Pair[K]](it.r).key
+}
+
+// A more complex test case testing type bounds (extracted from linalg.go2 and reduced to essence)
+
+type NumericAbs[T any] interface {
+       Abs() T
+}
+
+func AbsDifference[T NumericAbs[T]](x T)
+
+type OrderedAbs[T any] T
+
+func (a OrderedAbs[T]) Abs() OrderedAbs[T]
+
+func OrderedAbsDifference[T any](x T) {
+       AbsDifference(OrderedAbs[T](x))
+}
+
+// same code, reduced to essence
+
+func g[P interface{ m() P }](x P)
+
+type T4[P any] P
+
+func (_ T4[P]) m() T4[P]
+
+func _[Q any](x Q) {
+       g(T4[Q](x))
+}
+
+// Another test case that caused  problems in the past
+
+type T5[_ interface { a() }, _ interface{}] struct{}
+
+type A[P any] struct{ x P }
+
+func (_ A[P]) a() {}
+
+var _ T5[A[int], int]
+
+// Invoking methods with parameterized receiver types uses
+// type inference to determine the actual type arguments matching
+// the receiver type parameters from the actual receiver argument.
+// Go does implicit address-taking and dereferenciation depending
+// on the actual receiver and the method's receiver type. To make
+// type inference work, the type-checker matches "pointer-ness"
+// of the actual receiver and the method's receiver type.
+// The following code tests this mechanism.
+
+type R1[A any] struct{}
+func (_ R1[A]) vm()
+func (_ *R1[A]) pm()
+
+func _[T any](r R1[T], p *R1[T]) {
+       r.vm()
+       r.pm()
+       p.vm()
+       p.pm()
+}
+
+type R2[A, B any] struct{}
+func (_ R2[A, B]) vm()
+func (_ *R2[A, B]) pm()
+
+func _[T any](r R2[T, int], p *R2[string, T]) {
+       r.vm()
+       r.pm()
+       p.vm()
+       p.pm()
+}
+
+// An interface can (explicitly) declare at most one type list.
+type _ interface {
+       m0()
+       type int, string, bool
+       type /* ERROR multiple type lists */ float32, float64
+       m1()
+       m2()
+       type /* ERROR multiple type lists */ complex64, complex128
+       type /* ERROR multiple type lists */ rune
+}
+
+// Interface type lists may contain each type at most once.
+// (If there are multiple lists, we assume the author intended
+// for them to be all in a single list, and we report the error
+// as well.)
+type _ interface {
+       type int, int /* ERROR duplicate type int */
+       type /* ERROR multiple type lists */ int /* ERROR duplicate type int */
+}
+
+type _ interface {
+       type struct{f int}, struct{g int}, struct /* ERROR duplicate type */ {f int}
+}
+
+// Interface type lists can contain any type, incl. *Named types.
+// Verify that we use the underlying type to compute the operational type.
+type MyInt int
+func add1[T interface{type MyInt}](x T) T {
+       return x + 1
+}
+
+type MyString string
+func double[T interface{type MyInt, MyString}](x T) T {
+       return x + x
+}
+
+// Embedding of interfaces with type lists leads to interfaces
+// with type lists that are the intersection of the embedded
+// type lists.
+
+type E0 interface {
+       type int, bool, string
+}
+
+type E1 interface {
+       type int, float64, string
+}
+
+type E2 interface {
+       type float64
+}
+
+type I0 interface {
+       E0
+}
+
+func f0[T I0]()
+var _ = f0[int]
+var _ = f0[bool]
+var _ = f0[string]
+var _ = f0[float64 /* ERROR does not satisfy I0 */ ]
+
+type I01 interface {
+       E0
+       E1
+}
+
+func f01[T I01]()
+var _ = f01[int]
+var _ = f01[bool /* ERROR does not satisfy I0 */ ]
+var _ = f01[string]
+var _ = f01[float64 /* ERROR does not satisfy I0 */ ]
+
+type I012 interface {
+       E0
+       E1
+       E2
+}
+
+func f012[T I012]()
+var _ = f012[int /* ERROR does not satisfy I012 */ ]
+var _ = f012[bool /* ERROR does not satisfy I012 */ ]
+var _ = f012[string /* ERROR does not satisfy I012 */ ]
+var _ = f012[float64 /* ERROR does not satisfy I012 */ ]
+
+type I12 interface {
+       E1
+       E2
+}
+
+func f12[T I12]()
+var _ = f12[int /* ERROR does not satisfy I12 */ ]
+var _ = f12[bool /* ERROR does not satisfy I12 */ ]
+var _ = f12[string /* ERROR does not satisfy I12 */ ]
+var _ = f12[float64]
+
+type I0_ interface {
+       E0
+       type int
+}
+
+func f0_[T I0_]()
+var _ = f0_[int]
+var _ = f0_[bool /* ERROR does not satisfy I0_ */ ]
+var _ = f0_[string /* ERROR does not satisfy I0_ */ ]
+var _ = f0_[float64 /* ERROR does not satisfy I0_ */ ]
diff --git a/src/cmd/compile/internal/types2/testdata/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/typeparams.go2
new file mode 100644 (file)
index 0000000..04f5630
--- /dev/null
@@ -0,0 +1,430 @@
+// Copyright 2020 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
+
+// import "io" // for type assertion tests
+
+// The predeclared identifier "any" is only visible as a constraint
+// in a type parameter list.
+var _ any // ERROR undeclared
+func _[_ any /* ok here */ , _ interface{any /* ERROR undeclared */ }](any /* ERROR undeclared */ ) {
+        var _ any /* ERROR undeclared */
+}
+
+func identity[T any](x T) T { return x }
+
+func _[_ any](x int) int
+func _[T any](T /* ERROR redeclared */ T)()
+func _[T, T /* ERROR redeclared */ any]()
+
+func reverse[T any](list []T) []T {
+        rlist := make([]T, len(list))
+        i := len(list)
+        for _, x := range list {
+                i--
+                rlist[i] = x
+        }
+        return rlist
+}
+
+var _ = reverse /* ERROR cannot use generic function reverse */
+var _ = reverse[int, float32 /* ERROR got 2 type arguments */ ] ([]int{1, 2, 3})
+var _ = reverse[int]([ /* ERROR cannot use */ ]float32{1, 2, 3})
+var f = reverse[chan int]
+var _ = f(0 /* ERROR cannot convert 0 .* to \[\]chan int */ )
+
+func swap[A, B any](a A, b B) (B, A) { return b, a }
+
+var _ = swap /* ERROR single value is expected */ [int, float32](1, 2)
+var f32, i = swap[int, float32](swap[float32, int](1, 2))
+var _ float32 = f32
+var _ int = i
+
+func swapswap[A, B any](a A, b B) (A, B) {
+        return swap[B, A](b, a)
+}
+
+type F[A, B any] func(A, B) (B, A)
+
+func min[T interface{ type int }](x, y T) T {
+        if x < y {
+                return x
+        }
+        return y
+}
+
+func _[T interface{type int, float32}](x, y T) bool { return x < y }
+func _[T any](x, y T) bool { return x /* ERROR cannot compare */ < y }
+func _[T interface{type int, float32, bool}](x, y T) bool { return x /* ERROR cannot compare */ < y }
+
+func _[T C1[T]](x, y T) bool { return x /* ERROR cannot compare */ < y }
+func _[T C2[T]](x, y T) bool { return x < y }
+
+type C1[T any] interface{}
+type C2[T any] interface{ type int, float32 }
+
+func new[T any]() *T {
+        var x T
+        return &x
+}
+
+var _ = new /* ERROR cannot use generic function new */
+var _ *int = new[int]()
+
+func _[T any](map[T /* ERROR invalid map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable
+
+func f1[T1 any](struct{T1}) int
+var _ = f1[int](struct{T1}{})
+type T1 = int
+
+func f2[t1 any](struct{t1; x float32}) int
+var _ = f2[t1](struct{t1; x float32}{})
+type t1 = int
+
+
+func f3[A, B, C any](A, struct{x B}, func(A, struct{x B}, *C)) int
+
+var _ = f3[int, rune, bool](1, struct{x rune}{}, nil)
+
+// indexing
+
+func _[T any] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
+func _[T interface{ type int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
+func _[T interface{ type string }] (x T, i int) { _ = x[i] }
+func _[T interface{ type []int }] (x T, i int) { _ = x[i] }
+func _[T interface{ type [10]int, *[20]int, map[int]int }] (x T, i int) { _ = x[i] }
+func _[T interface{ type string, []byte }] (x T, i int) { _ = x[i] }
+func _[T interface{ type []int, [1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
+func _[T interface{ type string, []rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
+
+// indexing with various combinations of map types in type lists (see issue #42616)
+func _[T interface{ type []E, map[int]E }, E any](x T, i int) { _ = x[i] }
+func _[T interface{ type []E }, E any](x T, i int) { _ = &x[i] }
+func _[T interface{ type map[int]E }, E any](x T, i int) { _, _ = x[i] } // comma-ok permitted
+func _[T interface{ type []E, map[int]E }, E any](x T, i int) { _ = &x /* ERROR cannot take address */ [i] }
+func _[T interface{ type []E, map[int]E, map[uint]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // different map element types
+func _[T interface{ type []E, map[string]E }, E any](x T, i int) { _ = x[i /* ERROR cannot use i */ ] }
+
+// slicing
+// TODO(gri) implement this
+
+func _[T interface{ type string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] }
+
+// len/cap built-ins
+
+func _[T any](x T) { _ = len(x /* ERROR invalid argument */ ) }
+func _[T interface{ type int }](x T) { _ = len(x /* ERROR invalid argument */ ) }
+func _[T interface{ type string, []byte, int }](x T) { _ = len(x /* ERROR invalid argument */ ) }
+func _[T interface{ type string }](x T) { _ = len(x) }
+func _[T interface{ type [10]int }](x T) { _ = len(x) }
+func _[T interface{ type []byte }](x T) { _ = len(x) }
+func _[T interface{ type map[int]int }](x T) { _ = len(x) }
+func _[T interface{ type chan int }](x T) { _ = len(x) }
+func _[T interface{ type string, []byte, chan int }](x T) { _ = len(x) }
+
+func _[T any](x T) { _ = cap(x /* ERROR invalid argument */ ) }
+func _[T interface{ type int }](x T) { _ = cap(x /* ERROR invalid argument */ ) }
+func _[T interface{ type string, []byte, int }](x T) { _ = cap(x /* ERROR invalid argument */ ) }
+func _[T interface{ type string }](x T) { _ = cap(x /* ERROR invalid argument */ ) }
+func _[T interface{ type [10]int }](x T) { _ = cap(x) }
+func _[T interface{ type []byte }](x T) { _ = cap(x) }
+func _[T interface{ type map[int]int }](x T) { _ = cap(x /* ERROR invalid argument */ ) }
+func _[T interface{ type chan int }](x T) { _ = cap(x) }
+func _[T interface{ type []byte, chan int }](x T) { _ = cap(x) }
+
+// range iteration
+
+func _[T interface{}](x T) {
+        for range x /* ERROR cannot range */ {}
+}
+
+func _[T interface{ type string, []string }](x T) {
+        for range x {}
+        for i := range x { _ = i }
+        for i, _ := range x { _ = i }
+        for i, e := range x /* ERROR must have the same element type */ { _ = i }
+        for _, e := range x /* ERROR must have the same element type */ {}
+        var e rune
+        _ = e
+        for _, (e) = range x /* ERROR must have the same element type */ {}
+}
+
+
+func _[T interface{ type string, []rune, map[int]rune }](x T) {
+        for _, e := range x { _ = e }
+        for i, e := range x { _ = i; _ = e }
+}
+
+func _[T interface{ type string, []rune, map[string]rune }](x T) {
+        for _, e := range x { _ = e }
+        for i, e := range x /* ERROR must have the same key type */ { _ = e }
+}
+
+func _[T interface{ type string, chan int }](x T) {
+        for range x {}
+        for i := range x { _ = i }
+        for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value
+}
+
+func _[T interface{ type string, chan<-int }](x T) {
+        for i := range x /* ERROR send-only channel */ { _ = i }
+}
+
+// type inference checks
+
+var _ = new() /* ERROR cannot infer T */
+
+func f4[A, B, C any](A, B) C
+
+var _ = f4(1, 2) /* ERROR cannot infer C */
+var _ = f4[int, float32, complex128](1, 2)
+
+func f5[A, B, C any](A, []*B, struct{f []C}) int
+
+var _ = f5[int, float32, complex128](0, nil, struct{f []complex128}{})
+var _ = f5(0, nil, struct{f []complex128}{}) // ERROR cannot infer
+var _ = f5(0, []*float32{new[float32]()}, struct{f []complex128}{})
+
+func f6[A any](A, []A) int
+
+var _ = f6(0, nil)
+
+func f6nil[A any](A) int
+
+var _ = f6nil(nil) // ERROR cannot infer
+
+// type inference with variadic functions
+
+func f7[T any](...T) T
+
+var _ int = f7() /* ERROR cannot infer T */
+var _ int = f7(1)
+var _ int = f7(1, 2)
+var _ int = f7([]int{}...)
+var _ int = f7 /* ERROR cannot use */ ([]float64{}...)
+var _ float64 = f7([]float64{}...)
+var _ = f7[float64](1, 2.3)
+var _ = f7(float64(1), 2.3)
+var _ = f7(1, 2.3 /* ERROR does not match */ )
+var _ = f7(1.2, 3 /* ERROR does not match */ )
+
+func f8[A, B any](A, B, ...B) int
+
+var _ = f8(1) /* ERROR not enough arguments */
+var _ = f8(1, 2.3)
+var _ = f8(1, 2.3, 3.4, 4.5)
+var _ = f8(1, 2.3, 3.4, 4 /* ERROR does not match */ )
+var _ = f8[int, float64](1, 2.3, 3.4, 4)
+
+var _ = f8[int, float64](0, 0, nil...) // test case for #18268
+
+// init functions cannot have type parameters
+
+func init() {}
+func init[/* ERROR func init must have no type parameters */ _ any]() {}
+func init[/* ERROR func init must have no type parameters */ P any]() {}
+
+type T struct {}
+
+func (T) m1() {}
+// The type checker accepts method type parameters if configured accordingly.
+func (T) m2[_ any]() {}
+func (T) m3[P any]() {}
+
+// type inference across parameterized types
+
+type S1[P any] struct { f P }
+
+func f9[P any](x S1[P])
+
+func _() {
+        f9[int](S1[int]{42})
+       f9(S1[int]{42})
+}
+
+type S2[A, B, C any] struct{}
+
+func f10[X, Y, Z any](a S2[X, int, Z], b S2[X, Y, bool])
+
+func _[P any]() {
+        f10[int, float32, string](S2[int, int, string]{}, S2[int, float32, bool]{})
+        f10(S2[int, int, string]{}, S2[int, float32, bool]{})
+        f10(S2[P, int, P]{}, S2[P, float32, bool]{})
+}
+
+// corner case for type inference
+// (was bug: after instanting f11, the type-checker didn't mark f11 as non-generic)
+
+func f11[T any]()
+
+func _() {
+       f11[int]()
+}
+
+// the previous example was extracted from
+
+func f12[T interface{m() T}]()
+
+type A[T any] T
+
+func (a A[T]) m() A[T]
+
+func _[T any]() {
+       f12[A[T]]()
+}
+
+// method expressions
+
+func (_ S1[P]) m()
+
+func _() {
+       m := S1[int].m
+       m(struct { f int }{42})
+}
+
+func _[T any] (x T) {
+        m := S1[T].m
+        m(S1[T]{x})
+}
+
+// type parameters in methods (generalization)
+
+type R0 struct{}
+
+func (R0) _[T any](x T)
+func (R0 /* ERROR invalid receiver */ ) _[R0 any]() // scope of type parameters starts at "func"
+
+type R1[A, B any] struct{}
+
+func (_ R1[A, B]) m0(A, B)
+func (_ R1[A, B]) m1[T any](A, B, T) T
+func (_ R1 /* ERROR not a generic type */ [R1, _]) _()
+func (_ R1[A, B]) _[A /* ERROR redeclared */ any](B)
+
+func _() {
+        var r R1[int, string]
+        r.m1[rune](42, "foo", 'a')
+        r.m1[rune](42, "foo", 1.2 /* ERROR truncated to rune */)
+        r.m1(42, "foo", 1.2) // using type inference
+        var _ float64 = r.m1(42, "foo", 1.2)
+}
+
+type I1[A any] interface {
+        m1(A)
+}
+
+var _ I1[int] = r1[int]{}
+
+type r1[T any] struct{}
+
+func (_ r1[T]) m1(T)
+
+type I2[A, B any] interface {
+        m1(A)
+        m2(A) B
+}
+
+var _ I2[int, float32] = R2[int, float32]{}
+
+type R2[P, Q any] struct{}
+
+func (_ R2[X, Y]) m1(X)
+func (_ R2[X, Y]) m2(X) Y
+
+// type assertions and type switches over generic types
+// NOTE: These are currently disabled because it's unclear what the correct
+// approach is, and one can always work around by assigning the variable to
+// an interface first.
+
+// // ReadByte1 corresponds to the ReadByte example in the draft design.
+// func ReadByte1[T io.Reader](r T) (byte, error) {
+//     if br, ok := r.(io.ByteReader); ok {
+//             return br.ReadByte()
+//     }
+//     var b [1]byte
+//     _, err := r.Read(b[:])
+//     return b[0], err
+// }
+//
+// // ReadBytes2 is like ReadByte1 but uses a type switch instead.
+// func ReadByte2[T io.Reader](r T) (byte, error) {
+//         switch br := r.(type) {
+//         case io.ByteReader:
+//                 return br.ReadByte()
+//         }
+//     var b [1]byte
+//     _, err := r.Read(b[:])
+//     return b[0], err
+// }
+//
+// // type assertions and type switches over generic types are strict
+// type I3 interface {
+//         m(int)
+// }
+//
+// type I4 interface {
+//         m() int // different signature from I3.m
+// }
+//
+// func _[T I3](x I3, p T) {
+//         // type assertions and type switches over interfaces are not strict
+//         _ = x.(I4)
+//         switch x.(type) {
+//         case I4:
+//         }
+//
+//         // type assertions and type switches over generic types are strict
+//         _ = p /* ERROR cannot have dynamic type I4 */.(I4)
+//         switch p.(type) {
+//         case I4 /* ERROR cannot have dynamic type I4 */ :
+//         }
+// }
+
+// type assertions and type switches over generic types lead to errors for now
+
+func _[T any](x T) {
+       _ = x /* ERROR not an interface */ .(int)
+       switch x /* ERROR not an interface */ .(type) {
+       }
+
+       // work-around
+       var t interface{} = x
+       _ = t.(int)
+       switch t.(type) {
+       }
+}
+
+func _[T interface{type int}](x T) {
+       _ = x /* ERROR not an interface */ .(int)
+       switch x /* ERROR not an interface */ .(type) {
+       }
+
+       // work-around
+       var t interface{} = x
+       _ = t.(int)
+       switch t.(type) {
+       }
+}
+
+// error messages related to type bounds mention those bounds
+type C[P any] interface{}
+
+func _[P C[P]] (x P) {
+       x.m /* ERROR x.m undefined */ ()
+}
+
+type I interface {}
+
+func _[P I] (x P) {
+       x.m /* ERROR interface I has no method m */ ()
+}
+
+func _[P interface{}] (x P) {
+       x.m /* ERROR type bound for P has no method m */ ()
+}
+
+func _[P any] (x P) {
+       x.m /* ERROR type bound for P has no method m */ ()
+}
diff --git a/src/cmd/compile/internal/types2/testdata/vardecl.src b/src/cmd/compile/internal/types2/testdata/vardecl.src
new file mode 100644 (file)
index 0000000..9e48cdf
--- /dev/null
@@ -0,0 +1,214 @@
+// Copyright 2013 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 vardecl
+
+// Prerequisites.
+import "math"
+func f() {}
+func g() (x, y int) { return }
+var m map[string]int
+
+// Var decls must have a type or an initializer.
+var _ int
+var _, _ int
+
+var _ /* ERROR "expecting type" */
+var _, _ /* ERROR "expecting type" */
+var _, _, _ /* ERROR "expecting type" */
+
+// The initializer must be an expression.
+var _ = int /* ERROR "not an expression" */
+var _ = f /* ERROR "used as value" */ ()
+
+// Identifier and expression arity must match.
+var _, _ = 1, 2
+var _ = 1, 2 /* ERROR "extra init expr 2" */
+var _, _ = 1 /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */
+var _, _, _ /* ERROR "missing init expr for _" */ = 1, 2
+
+var _ = g /* ERROR "2-valued g" */ ()
+var _, _ = g()
+var _, _, _ = g /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */ ()
+
+var _ = m["foo"]
+var _, _ = m["foo"]
+var _, _, _ = m  /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */ ["foo"]
+
+var _, _ int = 1, 2
+var _ int = 1, 2 /* ERROR "extra init expr 2" */
+var _, _ int = 1 /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */
+var _, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
+
+var (
+       _, _ = 1, 2
+       _ = 1, 2 /* ERROR "extra init expr 2" */
+       _, _ = 1 /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */
+       _, _, _ /* ERROR "missing init expr for _" */ = 1, 2
+
+       _ = g /* ERROR "2-valued g" */ ()
+       _, _ = g()
+       _, _, _ = g /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */ ()
+
+       _ = m["foo"]
+       _, _ = m["foo"]
+       _, _, _ = m /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */ ["foo"]
+
+       _, _ int = 1, 2
+       _ int = 1, 2 /* ERROR "extra init expr 2" */
+       _, _ int = 1 /* ERROR "cannot initialize [0-9]+ variables with [0-9]+ values" */
+       _, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
+)
+
+// Variables declared in function bodies must be 'used'.
+type T struct{}
+func (r T) _(a, b, c int) (u, v, w int) {
+       var x1 /* ERROR "declared but not used" */ int
+       var x2 /* ERROR "declared but not used" */ int
+       x1 = 1
+       (x2) = 2
+
+       y1 /* ERROR "declared but not used" */ := 1
+       y2 /* ERROR "declared but not used" */ := 2
+       y1 = 1
+       (y1) = 2
+
+       {
+               var x1 /* ERROR "declared but not used" */ int
+               var x2 /* ERROR "declared but not used" */ int
+               x1 = 1
+               (x2) = 2
+
+               y1 /* ERROR "declared but not used" */ := 1
+               y2 /* ERROR "declared but not used" */ := 2
+               y1 = 1
+               (y1) = 2
+       }
+
+       if x /* ERROR "declared but not used" */ := 0; a < b {}
+
+       switch x /* ERROR "declared but not used" */, y := 0, 1; a {
+       case 0:
+               _ = y
+       case 1:
+               x /* ERROR "declared but not used" */ := 0
+       }
+
+       var t interface{}
+       switch t /* ERROR "declared but not used" */ := t.(type) {}
+
+       switch t /* ERROR "declared but not used" */ := t.(type) {
+       case int:
+       }
+
+       switch t /* ERROR "declared but not used" */ := t.(type) {
+       case int:
+       case float32, complex64:
+               t = nil
+       }
+
+       switch t := t.(type) {
+       case int:
+       case float32, complex64:
+               _ = t
+       }
+
+       switch t := t.(type) {
+       case int:
+       case float32:
+       case string:
+               _ = func() string {
+                       return t
+               }
+       }
+
+       switch t := t; t /* ERROR "declared but not used" */ := t.(type) {}
+
+       var z1 /* ERROR "declared but not used" */ int
+       var z2 int
+       _ = func(a, b, c int) (u, v, w int) {
+               z1 = a
+               (z1) = b
+               a = z2
+               return
+       }
+
+       var s []int
+       var i /* ERROR "declared but not used" */ , j int
+       for i, j = range s {
+               _ = j
+       }
+
+       for i, j /* ERROR "declared but not used" */ := range s {
+               _ = func() int {
+                       return i
+               }
+       }
+       return
+}
+
+// Unused variables in function literals must lead to only one error (issue #22524).
+func _() {
+       _ = func() {
+               var x /* ERROR declared but not used */ int
+       }
+}
+
+// Invalid variable declarations must not lead to "declared but not used errors".
+func _() {
+       var a x                        // ERROR undeclared name: x
+       var b = x                      // ERROR undeclared name: x
+       var c int = x                  // ERROR undeclared name: x
+       var d, e, f x                  /* ERROR x */ /* ERROR x */ /* ERROR x */
+       var g, h, i = x, x, x          /* ERROR x */ /* ERROR x */ /* ERROR x */
+       var j, k, l float32 = x, x, x  /* ERROR x */ /* ERROR x */ /* ERROR x */
+       // but no "declared but not used" errors
+}
+
+// Invalid (unused) expressions must not lead to spurious "declared but not used errors".
+func _() {
+       var a, b, c int
+       var x, y int
+       x, y = a /* ERROR cannot assign [0-9]+ values to [0-9]+ variables */ , b, c
+       _ = x
+       _ = y
+}
+
+func _() {
+       var x int
+       return x /* ERROR no result values expected */
+       return math /* ERROR no result values expected */ .Sin(0)
+}
+
+func _() int {
+       var x, y int
+       return /* ERROR wrong number of return values */ x, y
+}
+
+// Short variable declarations must declare at least one new non-blank variable.
+func _() {
+       _ := /* ERROR no new variables */ 0
+       _, a := 0, 1
+       _, a := /* ERROR no new variables */ 0, 1
+       _, a, b := 0, 1, 2
+       _, _, _ := /* ERROR no new variables */ 0, 1, 2
+
+       _ = a
+       _ = b
+}
+
+// Test case for variables depending on function literals (see also #22992).
+var A /* ERROR initialization cycle */ = func() int { return A }()
+
+func _() {
+       // The function literal below must not see a.
+       var a = func() int { return a /* ERROR "undeclared name" */ }()
+       var _ = func() int { return a }()
+
+       // The function literal below must not see x, y, or z.
+       var x, y, z = 0, 1, func() int { return x /* ERROR "undeclared name" */ + y /* ERROR "undeclared name" */ + z /* ERROR "undeclared name" */ }()
+       _, _, _ = x, y, z
+}
+
+// TODO(gri) consolidate other var decl checks in this file
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go
new file mode 100644 (file)
index 0000000..1bfde41
--- /dev/null
@@ -0,0 +1,1060 @@
+// UNREVIEWED
+// Copyright 2011 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 (
+       "cmd/compile/internal/syntax"
+       "fmt"
+       "sort"
+)
+
+// A Type represents a type of Go.
+// All types implement the Type interface.
+type Type interface {
+       // Underlying returns the underlying type of a type
+       // w/o following forwarding chains. Only used by
+       // client packages (here for backward-compatibility).
+       Underlying() Type
+
+       // Under returns the true expanded underlying type.
+       // If it doesn't exist, the result is Typ[Invalid].
+       // Under must only be called when a type is known
+       // to be fully set up.
+       Under() Type
+
+       // String returns a string representation of a type.
+       String() string
+
+       // Converters
+       // A converter must only be called when a type is
+       // known to be fully set up. A converter returns
+       // a type's operational type (see comment for optype)
+       // or nil if the type is receiver is not of the
+       // respective type.
+       Basic() *Basic
+       Array() *Array
+       Slice() *Slice
+       Struct() *Struct
+       Pointer() *Pointer
+       Tuple() *Tuple
+       Signature() *Signature
+       Sum() *Sum
+       Interface() *Interface
+       Map() *Map
+       Chan() *Chan
+
+       // If the receiver for Named and TypeParam is of
+       // the respective type (possibly after unpacking
+       // an instance type), these methods return that
+       // type. Otherwise the result is nil.
+       Named() *Named
+       TypeParam() *TypeParam
+}
+
+// aType implements default type behavior
+type aType struct{}
+
+// These methods must be implemented by each type.
+func (aType) Underlying() Type { panic("unreachable") }
+func (aType) Under() Type      { panic("unreachable") }
+func (aType) String() string   { panic("unreachable") }
+
+// Each type is implementing its version of these methods
+// (Basic must implement Basic, etc.), the other methods
+// are inherited.
+func (aType) Basic() *Basic         { return nil }
+func (aType) Array() *Array         { return nil }
+func (aType) Slice() *Slice         { return nil }
+func (aType) Struct() *Struct       { return nil }
+func (aType) Pointer() *Pointer     { return nil }
+func (aType) Tuple() *Tuple         { return nil }
+func (aType) Signature() *Signature { return nil }
+func (aType) Sum() *Sum             { return nil }
+func (aType) Interface() *Interface { return nil }
+func (aType) Map() *Map             { return nil }
+func (aType) Chan() *Chan           { return nil }
+
+func (aType) Named() *Named         { return nil }
+func (aType) TypeParam() *TypeParam { return nil }
+
+// BasicKind describes the kind of basic type.
+type BasicKind int
+
+const (
+       Invalid BasicKind = iota // type is invalid
+
+       // predeclared types
+       Bool
+       Int
+       Int8
+       Int16
+       Int32
+       Int64
+       Uint
+       Uint8
+       Uint16
+       Uint32
+       Uint64
+       Uintptr
+       Float32
+       Float64
+       Complex64
+       Complex128
+       String
+       UnsafePointer
+
+       // types for untyped values
+       UntypedBool
+       UntypedInt
+       UntypedRune
+       UntypedFloat
+       UntypedComplex
+       UntypedString
+       UntypedNil
+
+       // aliases
+       Byte = Uint8
+       Rune = Int32
+)
+
+// BasicInfo is a set of flags describing properties of a basic type.
+type BasicInfo int
+
+// Properties of basic types.
+const (
+       IsBoolean BasicInfo = 1 << iota
+       IsInteger
+       IsUnsigned
+       IsFloat
+       IsComplex
+       IsString
+       IsUntyped
+
+       IsOrdered   = IsInteger | IsFloat | IsString
+       IsNumeric   = IsInteger | IsFloat | IsComplex
+       IsConstType = IsBoolean | IsNumeric | IsString
+)
+
+// A Basic represents a basic type.
+type Basic struct {
+       kind BasicKind
+       info BasicInfo
+       name string
+       aType
+}
+
+// Kind returns the kind of basic type b.
+func (b *Basic) Kind() BasicKind { return b.kind }
+
+// Info returns information about properties of basic type b.
+func (b *Basic) Info() BasicInfo { return b.info }
+
+// Name returns the name of basic type b.
+func (b *Basic) Name() string { return b.name }
+
+// An Array represents an array type.
+type Array struct {
+       len  int64
+       elem Type
+       aType
+}
+
+// NewArray returns a new array type for the given element type and length.
+// A negative length indicates an unknown length.
+func NewArray(elem Type, len int64) *Array { return &Array{len: len, elem: elem} }
+
+// Len returns the length of array a.
+// A negative result indicates an unknown length.
+func (a *Array) Len() int64 { return a.len }
+
+// Elem returns element type of array a.
+func (a *Array) Elem() Type { return a.elem }
+
+// A Slice represents a slice type.
+type Slice struct {
+       elem Type
+       aType
+}
+
+// NewSlice returns a new slice type for the given element type.
+func NewSlice(elem Type) *Slice { return &Slice{elem: elem} }
+
+// Elem returns the element type of slice s.
+func (s *Slice) Elem() Type { return s.elem }
+
+// A Struct represents a struct type.
+type Struct struct {
+       fields []*Var
+       tags   []string // field tags; nil if there are no tags
+       aType
+}
+
+// NewStruct returns a new struct with the given fields and corresponding field tags.
+// If a field with index i has a tag, tags[i] must be that tag, but len(tags) may be
+// only as long as required to hold the tag with the largest index i. Consequently,
+// if no field has a tag, tags may be nil.
+func NewStruct(fields []*Var, tags []string) *Struct {
+       var fset objset
+       for _, f := range fields {
+               if f.name != "_" && fset.insert(f) != nil {
+                       panic("multiple fields with the same name")
+               }
+       }
+       if len(tags) > len(fields) {
+               panic("more tags than fields")
+       }
+       return &Struct{fields: fields, tags: tags}
+}
+
+// NumFields returns the number of fields in the struct (including blank and embedded fields).
+func (s *Struct) NumFields() int { return len(s.fields) }
+
+// Field returns the i'th field for 0 <= i < NumFields().
+func (s *Struct) Field(i int) *Var { return s.fields[i] }
+
+// Tag returns the i'th field tag for 0 <= i < NumFields().
+func (s *Struct) Tag(i int) string {
+       if i < len(s.tags) {
+               return s.tags[i]
+       }
+       return ""
+}
+
+// A Pointer represents a pointer type.
+type Pointer struct {
+       base Type // element type
+       aType
+}
+
+// NewPointer returns a new pointer type for the given element (base) type.
+func NewPointer(elem Type) *Pointer { return &Pointer{base: elem} }
+
+// Elem returns the element type for the given pointer p.
+func (p *Pointer) Elem() Type { return p.base }
+
+// A Tuple represents an ordered list of variables; a nil *Tuple is a valid (empty) tuple.
+// Tuples are used as components of signatures and to represent the type of multiple
+// assignments; they are not first class types of Go.
+type Tuple struct {
+       vars []*Var
+       aType
+}
+
+// NewTuple returns a new tuple for the given variables.
+func NewTuple(x ...*Var) *Tuple {
+       if len(x) > 0 {
+               return &Tuple{vars: x}
+       }
+       return nil
+}
+
+// We cannot rely on the embedded X() *X methods because (*Tuple)(nil)
+// is a valid *Tuple value but (*Tuple)(nil).X() would panic without
+// these implementations. At the moment we only need X = Basic, Named,
+// but add all because missing one leads to very confusing bugs.
+// TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer;
+//           it's too subtle and causes problems.
+func (*Tuple) Basic() *Basic     { return nil }
+func (*Tuple) Array() *Array     { return nil }
+func (*Tuple) Slice() *Slice     { return nil }
+func (*Tuple) Struct() *Struct   { return nil }
+func (*Tuple) Pointer() *Pointer { return nil }
+
+// func (*Tuple) Tuple() *Tuple      // implemented below
+func (*Tuple) Signature() *Signature { return nil }
+func (*Tuple) Sum() *Sum             { return nil }
+func (*Tuple) Interface() *Interface { return nil }
+func (*Tuple) Map() *Map             { return nil }
+func (*Tuple) Chan() *Chan           { return nil }
+
+func (*Tuple) Named() *Named         { return nil }
+func (*Tuple) TypeParam() *TypeParam { return nil }
+
+// Len returns the number variables of tuple t.
+func (t *Tuple) Len() int {
+       if t != nil {
+               return len(t.vars)
+       }
+       return 0
+}
+
+// At returns the i'th variable of tuple t.
+func (t *Tuple) At(i int) *Var { return t.vars[i] }
+
+// A Signature represents a (non-builtin) function or method type.
+// The receiver is ignored when comparing signatures for identity.
+type Signature struct {
+       // We need to keep the scope in Signature (rather than passing it around
+       // 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  []*TypeName // reveiver type parameters from left to right; or nil
+       tparams  []*TypeName // 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)
+       aType
+}
+
+// NewSignature returns a new function type for the given receiver, parameters,
+// and results, either of which may be nil. If variadic is set, the function
+// is variadic, it must have at least one parameter, and the last parameter
+// must be of unnamed slice type.
+func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
+       if variadic {
+               n := params.Len()
+               if n == 0 {
+                       panic("types.NewSignature: variadic function must have at least one parameter")
+               }
+               if _, ok := params.At(n - 1).typ.(*Slice); !ok {
+                       panic("types.NewSignature: variadic parameter must be of unnamed slice type")
+               }
+       }
+       return &Signature{recv: recv, params: params, results: results, variadic: variadic}
+}
+
+// Recv returns the receiver of signature s (if a method), or nil if a
+// function. It is ignored when comparing signatures for identity.
+//
+// For an abstract method, Recv returns the enclosing interface either
+// as a *Named or an *Interface. Due to embedding, an interface may
+// 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() []*TypeName { return s.tparams }
+
+// SetTParams sets the type parameters of signature s.
+func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams }
+
+// Params returns the parameters of signature s, or nil.
+func (s *Signature) Params() *Tuple { return s.params }
+
+// Results returns the results of signature s, or nil.
+func (s *Signature) Results() *Tuple { return s.results }
+
+// Variadic reports whether the signature s is variadic.
+func (s *Signature) Variadic() bool { return s.variadic }
+
+// A Sum represents a set of possible types.
+// Sums are currently used to represent type lists of interfaces
+// and thus the underlying types of type parameters; they are not
+// first class types of Go.
+type Sum struct {
+       types []Type // types are unique
+       aType
+}
+
+// NewSum returns a new Sum type consisting of the provided
+// types if there are more than one. If there is exactly one
+// type, it returns that type. If the list of types is empty
+// the result is nil.
+func NewSum(types []Type) Type {
+       if len(types) == 0 {
+               return nil
+       }
+
+       // What should happen if types contains a sum type?
+       // Do we flatten the types list? For now we check
+       // and panic. This should not be possible for the
+       // current use case of type lists.
+       // TODO(gri) Come up with the rules for sum types.
+       for _, t := range types {
+               if _, ok := t.(*Sum); ok {
+                       panic("sum type contains sum type - unimplemented")
+               }
+       }
+
+       if len(types) == 1 {
+               return types[0]
+       }
+       return &Sum{types: types}
+}
+
+// is reports whether all types in t satisfy pred.
+func (s *Sum) is(pred func(Type) bool) bool {
+       if s == nil {
+               return false
+       }
+       for _, t := range s.types {
+               if !pred(t) {
+                       return false
+               }
+       }
+       return true
+}
+
+// An Interface represents an interface type.
+type Interface struct {
+       methods   []*Func // ordered list of explicitly declared methods
+       types     Type    // (possibly a Sum) type declared with a type list (TODO(gri) need better field name)
+       embeddeds []Type  // ordered list of explicitly embedded types
+
+       allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset)
+       allTypes   Type    // intersection of all embedded and locally declared types  (TODO(gri) need better field name)
+
+       obj Object // type declaration defining this interface; or nil (for better error messages)
+
+       aType
+}
+
+// unpack unpacks a type into a list of types.
+// TODO(gri) Try to eliminate the need for this function.
+func unpack(typ Type) []Type {
+       if typ == nil {
+               return nil
+       }
+       if sum := typ.Sum(); sum != nil {
+               return sum.types
+       }
+       return []Type{typ}
+}
+
+// is reports whether interface t represents types that all satisfy pred.
+func (t *Interface) is(pred func(Type) bool) bool {
+       if t.allTypes == nil {
+               return false // we must have at least one type! (was bug)
+       }
+       for _, t := range unpack(t.allTypes) {
+               if !pred(t) {
+                       return false
+               }
+       }
+       return true
+}
+
+// emptyInterface represents the empty (completed) interface
+var emptyInterface = Interface{allMethods: markComplete}
+
+// markComplete is used to mark an empty interface as completely
+// set up by setting the allMethods field to a non-nil empty slice.
+var markComplete = make([]*Func, 0)
+
+// NewInterface returns a new (incomplete) interface for the given methods and embedded types.
+// Each embedded type must have an underlying type of interface type.
+// NewInterface takes ownership of the provided methods and may modify their types by setting
+// missing receivers. To compute the method set of the interface, Complete must be called.
+//
+// Deprecated: Use NewInterfaceType instead which allows any (even non-defined) interface types
+// to be embedded. This is necessary for interfaces that embed alias type names referring to
+// non-defined (literal) interface types.
+func NewInterface(methods []*Func, embeddeds []*Named) *Interface {
+       tnames := make([]Type, len(embeddeds))
+       for i, t := range embeddeds {
+               tnames[i] = t
+       }
+       return NewInterfaceType(methods, tnames)
+}
+
+// NewInterfaceType returns a new (incomplete) interface for the given methods and embedded types.
+// Each embedded type must have an underlying type of interface type (this property is not
+// verified for defined types, which may be in the process of being set up and which don't
+// have a valid underlying type yet).
+// NewInterfaceType takes ownership of the provided methods and may modify their types by setting
+// missing receivers. To compute the method set of the interface, Complete must be called.
+func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
+       if len(methods) == 0 && len(embeddeds) == 0 {
+               return &emptyInterface
+       }
+
+       // set method receivers if necessary
+       typ := new(Interface)
+       for _, m := range methods {
+               if sig := m.typ.(*Signature); sig.recv == nil {
+                       sig.recv = NewVar(m.pos, m.pkg, "", typ)
+               }
+       }
+
+       // All embedded types should be interfaces; however, defined types
+       // may not yet be fully resolved. Only verify that non-defined types
+       // are interfaces. This matches the behavior of the code before the
+       // fix for #25301 (issue #25596).
+       for _, t := range embeddeds {
+               if _, ok := t.(*Named); !ok && !IsInterface(t) {
+                       panic("embedded type is not an interface")
+               }
+       }
+
+       // sort for API stability
+       sort.Sort(byUniqueMethodName(methods))
+       sort.Stable(byUniqueTypeName(embeddeds))
+
+       typ.methods = methods
+       typ.embeddeds = embeddeds
+       return typ
+}
+
+// NumExplicitMethods returns the number of explicitly declared methods of interface t.
+func (t *Interface) NumExplicitMethods() int { return len(t.methods) }
+
+// ExplicitMethod returns the i'th explicitly declared method of interface t for 0 <= i < t.NumExplicitMethods().
+// The methods are ordered by their unique Id.
+func (t *Interface) ExplicitMethod(i int) *Func { return t.methods[i] }
+
+// NumEmbeddeds returns the number of embedded types in interface t.
+func (t *Interface) NumEmbeddeds() int { return len(t.embeddeds) }
+
+// Embedded returns the i'th embedded defined (*Named) type of interface t for 0 <= i < t.NumEmbeddeds().
+// The result is nil if the i'th embedded type is not a defined type.
+//
+// Deprecated: Use EmbeddedType which is not restricted to defined (*Named) types.
+func (t *Interface) Embedded(i int) *Named { tname, _ := t.embeddeds[i].(*Named); return tname }
+
+// EmbeddedType returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds().
+func (t *Interface) EmbeddedType(i int) Type { return t.embeddeds[i] }
+
+// NumMethods returns the total number of methods of interface t.
+// The interface must have been completed.
+func (t *Interface) NumMethods() int { t.assertCompleteness(); return len(t.allMethods) }
+
+func (t *Interface) assertCompleteness() {
+       if t.allMethods == nil {
+               panic("interface is incomplete")
+       }
+}
+
+// Method returns the i'th method of interface t for 0 <= i < t.NumMethods().
+// The methods are ordered by their unique Id.
+// The interface must have been completed.
+func (t *Interface) Method(i int) *Func { t.assertCompleteness(); return t.allMethods[i] }
+
+// Empty reports whether t is the empty interface.
+func (t *Interface) Empty() bool {
+       if t.allMethods != nil {
+               // interface is complete - quick test
+               // A non-nil allTypes may still be empty and represents the bottom type.
+               return len(t.allMethods) == 0 && t.allTypes == nil
+       }
+       return !t.iterate(func(t *Interface) bool {
+               if len(t.methods) > 0 || t.types != nil {
+                       return true
+               }
+               return false
+       }, nil)
+}
+
+// HasTypeList reports whether interface t has a type list, possibly from an embedded type.
+func (t *Interface) HasTypeList() bool {
+       if t.allMethods != nil {
+               // interface is complete - quick test
+               return t.allTypes != nil
+       }
+
+       return t.iterate(func(t *Interface) bool {
+               if t.types != nil {
+                       return true
+               }
+               return false
+       }, nil)
+}
+
+// IsComparable reports whether interface t is or embeds the predeclared interface "comparable".
+func (t *Interface) IsComparable() bool {
+       if t.allMethods != nil {
+               // interface is complete - quick test
+               _, m := lookupMethod(t.allMethods, nil, "==")
+               return m != nil
+       }
+
+       return t.iterate(func(t *Interface) bool {
+               _, m := lookupMethod(t.methods, nil, "==")
+               return m != nil
+       }, nil)
+}
+
+// IsConstraint reports t.HasTypeList() || t.IsComparable().
+func (t *Interface) IsConstraint() bool {
+       if t.allMethods != nil {
+               // interface is complete - quick test
+               if t.allTypes != nil {
+                       return true
+               }
+               _, m := lookupMethod(t.allMethods, nil, "==")
+               return m != nil
+       }
+
+       return t.iterate(func(t *Interface) bool {
+               if t.types != nil {
+                       return true
+               }
+               _, m := lookupMethod(t.methods, nil, "==")
+               return m != nil
+       }, nil)
+}
+
+// iterate calls f with t and then with any embedded interface of t, recursively, until f returns true.
+// iterate reports whether any call to f returned true.
+func (t *Interface) iterate(f func(*Interface) bool, seen map[*Interface]bool) bool {
+       if f(t) {
+               return true
+       }
+       for _, e := range t.embeddeds {
+               // e should be an interface but be careful (it may be invalid)
+               if e := e.Interface(); e != nil {
+                       // Cyclic interfaces such as "type E interface { E }" are not permitted
+                       // but they are still constructed and we need to detect such cycles.
+                       if seen[e] {
+                               continue
+                       }
+                       if seen == nil {
+                               seen = make(map[*Interface]bool)
+                       }
+                       seen[e] = true
+                       if e.iterate(f, seen) {
+                               return true
+                       }
+               }
+       }
+       return false
+}
+
+// isSatisfiedBy reports whether interface t's type list is satisfied by the type typ.
+// If the the type list is empty (absent), typ trivially satisfies the interface.
+// TODO(gri) This is not a great name. Eventually, we should have a more comprehensive
+//           "implements" predicate.
+func (t *Interface) isSatisfiedBy(typ Type) bool {
+       t.Complete()
+       if t.allTypes == nil {
+               return true
+       }
+       types := unpack(t.allTypes)
+       return includes(types, typ) || includes(types, typ.Under())
+}
+
+// Complete computes the interface's method set. It must be called by users of
+// NewInterfaceType and NewInterface after the interface's embedded types are
+// fully defined and before using the interface type in any way other than to
+// form other types. The interface must not contain duplicate methods or a
+// panic occurs. Complete returns the receiver.
+func (t *Interface) Complete() *Interface {
+       // TODO(gri) consolidate this method with Checker.completeInterface
+       if t.allMethods != nil {
+               return t
+       }
+
+       t.allMethods = markComplete // avoid infinite recursion
+
+       var todo []*Func
+       var methods []*Func
+       var seen objset
+       addMethod := func(m *Func, explicit bool) {
+               switch other := seen.insert(m); {
+               case other == nil:
+                       methods = append(methods, m)
+               case explicit:
+                       panic("duplicate method " + m.name)
+               default:
+                       // check method signatures after all locally embedded interfaces are computed
+                       todo = append(todo, m, other.(*Func))
+               }
+       }
+
+       for _, m := range t.methods {
+               addMethod(m, true)
+       }
+
+       allTypes := t.types
+
+       for _, typ := range t.embeddeds {
+               utyp := typ.Under()
+               etyp := utyp.Interface()
+               if etyp == nil {
+                       if utyp != Typ[Invalid] {
+                               panic(fmt.Sprintf("%s is not an interface", typ))
+                       }
+                       continue
+               }
+               etyp.Complete()
+               for _, m := range etyp.allMethods {
+                       addMethod(m, false)
+               }
+               allTypes = intersect(allTypes, etyp.allTypes)
+       }
+
+       for i := 0; i < len(todo); i += 2 {
+               m := todo[i]
+               other := todo[i+1]
+               if !Identical(m.typ, other.typ) {
+                       panic("duplicate method " + m.name)
+               }
+       }
+
+       if methods != nil {
+               sort.Sort(byUniqueMethodName(methods))
+               t.allMethods = methods
+       }
+       t.allTypes = allTypes
+
+       return t
+}
+
+// A Map represents a map type.
+type Map struct {
+       key, elem Type
+       aType
+}
+
+// NewMap returns a new map for the given key and element types.
+func NewMap(key, elem Type) *Map {
+       return &Map{key: key, elem: elem}
+}
+
+// Key returns the key type of map m.
+func (m *Map) Key() Type { return m.key }
+
+// Elem returns the element type of map m.
+func (m *Map) Elem() Type { return m.elem }
+
+// A Chan represents a channel type.
+type Chan struct {
+       dir  ChanDir
+       elem Type
+       aType
+}
+
+// A ChanDir value indicates a channel direction.
+type ChanDir int
+
+// The direction of a channel is indicated by one of these constants.
+const (
+       SendRecv ChanDir = iota
+       SendOnly
+       RecvOnly
+)
+
+// NewChan returns a new channel type for the given direction and element type.
+func NewChan(dir ChanDir, elem Type) *Chan {
+       return &Chan{dir: dir, elem: elem}
+}
+
+// Dir returns the direction of channel c.
+func (c *Chan) Dir() ChanDir { return c.dir }
+
+// Elem returns the element type of channel c.
+func (c *Chan) Elem() Type { return c.elem }
+
+// A Named represents a named (defined) type.
+type Named struct {
+       check      *Checker    // for Named.Under implementation
+       info       typeInfo    // for cycle detection
+       obj        *TypeName   // corresponding declared object
+       orig       Type        // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
+       underlying Type        // possibly a *Named during setup; never a *Named once set up completely
+       tparams    []*TypeName // type parameters, or nil
+       targs      []Type      // 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
+       aType
+}
+
+// NewNamed returns a new named type for the given type name, underlying type, and associated methods.
+// If the given type name obj doesn't have a type yet, its type is set to the returned named type.
+// The underlying type must not be a *Named.
+func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
+       if _, ok := underlying.(*Named); ok {
+               panic("types.NewNamed: underlying type must not be *Named")
+       }
+       typ := &Named{obj: obj, orig: underlying, underlying: underlying, methods: methods}
+       if obj.typ == nil {
+               obj.typ = typ
+       }
+       return typ
+}
+
+func (check *Checker) NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
+       typ := &Named{check: check, obj: obj, orig: underlying, underlying: underlying, methods: methods}
+       if obj.typ == nil {
+               obj.typ = typ
+       }
+       return typ
+}
+
+// Obj returns the type name for the named type t.
+func (t *Named) Obj() *TypeName { return t.obj }
+
+// Converter methods
+func (t *Named) Basic() *Basic         { return t.Under().Basic() }
+func (t *Named) Array() *Array         { return t.Under().Array() }
+func (t *Named) Slice() *Slice         { return t.Under().Slice() }
+func (t *Named) Struct() *Struct       { return t.Under().Struct() }
+func (t *Named) Pointer() *Pointer     { return t.Under().Pointer() }
+func (t *Named) Tuple() *Tuple         { return t.Under().Tuple() }
+func (t *Named) Signature() *Signature { return t.Under().Signature() }
+func (t *Named) Interface() *Interface { return t.Under().Interface() }
+func (t *Named) Map() *Map             { return t.Under().Map() }
+func (t *Named) Chan() *Chan           { return t.Under().Chan() }
+
+// func (t *Named) Named() *Named      // declared below
+func (t *Named) TypeParam() *TypeParam { return t.Under().TypeParam() }
+
+// 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.
+// The result is non-nil for an (originally) parameterized type even if it is instantiated.
+func (t *Named) TParams() []*TypeName { return t.tparams }
+
+// TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated.
+func (t *Named) TArgs() []Type { return t.targs }
+
+// SetTArgs sets the type arguments of Named.
+func (t *Named) SetTArgs(args []Type) { t.targs = args }
+
+// NumMethods returns the number of explicit methods whose receiver is named type t.
+func (t *Named) NumMethods() int { return len(t.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.methods[i] }
+
+// SetUnderlying sets the underlying type and marks t as complete.
+func (t *Named) SetUnderlying(underlying Type) {
+       if underlying == nil {
+               panic("types.Named.SetUnderlying: underlying type must not be nil")
+       }
+       if _, ok := underlying.(*Named); ok {
+               panic("types.Named.SetUnderlying: underlying type must not be *Named")
+       }
+       t.underlying = underlying
+}
+
+// AddMethod adds method m unless it is already in the method list.
+func (t *Named) AddMethod(m *Func) {
+       if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 {
+               t.methods = append(t.methods, m)
+       }
+}
+
+// A TypeParam represents a type parameter type.
+type TypeParam struct {
+       check *Checker  // for lazy type bound completion
+       id    uint64    // unique id
+       obj   *TypeName // corresponding type name
+       index int       // parameter index
+       bound Type      // *Named or *Interface; underlying type is always *Interface
+       aType
+}
+
+// NewTypeParam returns a new TypeParam.
+func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam {
+       assert(bound != nil)
+       typ := &TypeParam{check: check, id: check.nextId, obj: obj, index: index, bound: bound}
+       check.nextId++
+       if obj.typ == nil {
+               obj.typ = typ
+       }
+       return typ
+}
+
+func (t *TypeParam) Bound() *Interface {
+       iface := t.bound.Interface()
+       // use the type bound position if we have one
+       pos := nopos
+       if n, _ := t.bound.(*Named); n != nil {
+               pos = n.obj.pos
+       }
+       t.check.completeInterface(pos, iface)
+       return iface
+}
+
+// optype returns a type's operational type. Except for
+// type parameters, the operational type is the same
+// as the underlying type (as returned by Under). For
+// Type parameters, the operational type is determined
+// by the corresponding type bound's type list. The
+// result may be the bottom or top type, but it is never
+// the incoming type parameter.
+func optype(typ Type) Type {
+       if t := typ.TypeParam(); t != nil {
+               // If the optype is typ, return the top type as we have
+               // no information. It also prevents infinite recursion
+               // via the TypeParam converter methods. This can happen
+               // for a type parameter list of the form:
+               // (type T interface { type T }).
+               // See also issue #39680.
+               if u := t.Bound().allTypes; u != nil && u != typ {
+                       // u != typ and u is a type parameter => u.Under() != typ, so this is ok
+                       return u.Under()
+               }
+               return theTop
+       }
+       return typ
+}
+
+// Converter methods
+func (t *TypeParam) Basic() *Basic         { return optype(t).Basic() }
+func (t *TypeParam) Array() *Array         { return optype(t).Array() }
+func (t *TypeParam) Slice() *Slice         { return optype(t).Slice() }
+func (t *TypeParam) Struct() *Struct       { return optype(t).Struct() }
+func (t *TypeParam) Pointer() *Pointer     { return optype(t).Pointer() }
+func (t *TypeParam) Tuple() *Tuple         { return optype(t).Tuple() }
+func (t *TypeParam) Signature() *Signature { return optype(t).Signature() }
+func (t *TypeParam) Sum() *Sum             { return optype(t).Sum() }
+func (t *TypeParam) Interface() *Interface { return optype(t).Interface() }
+func (t *TypeParam) Map() *Map             { return optype(t).Map() }
+func (t *TypeParam) Chan() *Chan           { return optype(t).Chan() }
+
+// func (t *TypeParam) Named() *Named         // Named does not unpack type parameters
+// func (t *TypeParam) TypeParam() *TypeParam // declared below
+
+// An instance represents an instantiated generic type syntactically
+// (without expanding the instantiation). Type instances appear only
+// during type-checking and are replaced by their fully instantiated
+// (expanded) types before the end of type-checking.
+type instance struct {
+       check   *Checker     // for lazy instantiation
+       pos     syntax.Pos   // position of type instantiation; for error reporting only
+       base    *Named       // parameterized type to be instantiated
+       targs   []Type       // type arguments
+       poslist []syntax.Pos // position of each targ; for error reporting only
+       value   Type         // base(targs...) after instantiation or Typ[Invalid]; nil if not yet set
+       aType
+}
+
+// Converter methods
+func (t *instance) Basic() *Basic         { return t.Under().Basic() }
+func (t *instance) Array() *Array         { return t.Under().Array() }
+func (t *instance) Slice() *Slice         { return t.Under().Slice() }
+func (t *instance) Struct() *Struct       { return t.Under().Struct() }
+func (t *instance) Pointer() *Pointer     { return t.Under().Pointer() }
+func (t *instance) Tuple() *Tuple         { return t.Under().Tuple() }
+func (t *instance) Signature() *Signature { return t.Under().Signature() }
+func (t *instance) Sum() *Sum             { return t.Under().Sum() }
+func (t *instance) Interface() *Interface { return t.Under().Interface() }
+func (t *instance) Map() *Map             { return t.Under().Map() }
+func (t *instance) Chan() *Chan           { return t.Under().Chan() }
+
+func (t *instance) Named() *Named         { return t.expand().Named() }
+func (t *instance) TypeParam() *TypeParam { return t.expand().TypeParam() }
+
+// expand returns the instantiated (= expanded) type of t.
+// The result is either an instantiated *Named type, or
+// Typ[Invalid] if there was an error.
+func (t *instance) expand() Type {
+       v := t.value
+       if v == nil {
+               v = t.check.instantiate(t.pos, t.base, t.targs, t.poslist)
+               if v == nil {
+                       v = Typ[Invalid]
+               }
+               t.value = v
+       }
+       // After instantiation we must have an invalid or a *Named type.
+       if debug && v != Typ[Invalid] {
+               _ = v.(*Named)
+       }
+       return v
+}
+
+// expand expands a type instance into its instantiated
+// type and leaves all other types alone. expand does
+// not recurse.
+func expand(typ Type) Type {
+       if t, _ := typ.(*instance); t != nil {
+               return t.expand()
+       }
+       return typ
+}
+
+// expandf is set to expand.
+// Call expandf when calling expand causes compile-time cycle error.
+var expandf func(Type) Type
+
+func init() { expandf = expand }
+
+// bottom represents the bottom of the type lattice.
+// It is the underlying type of a type parameter that
+// cannot be satisfied by any type, usually because
+// the intersection of type constraints left nothing).
+type bottom struct {
+       aType
+}
+
+// theBottom is the singleton bottom type.
+var theBottom = &bottom{}
+
+// top represents the top of the type lattice.
+// It is the underlying type of a type parameter that
+// can be satisfied by any type (ignoring methods),
+// usually because the type constraint has no type
+// list.
+type top struct {
+       aType
+}
+
+// theTop is the singleton top type.
+var theTop = &top{}
+
+// Type-specific implementations of type converters.
+func (t *Basic) Basic() *Basic             { return t }
+func (t *Array) Array() *Array             { return t }
+func (t *Slice) Slice() *Slice             { return t }
+func (t *Struct) Struct() *Struct          { return t }
+func (t *Pointer) Pointer() *Pointer       { return t }
+func (t *Tuple) Tuple() *Tuple             { return t }
+func (t *Signature) Signature() *Signature { return t }
+func (t *Sum) Sum() *Sum                   { return t }
+func (t *Interface) Interface() *Interface { return t }
+func (t *Map) Map() *Map                   { return t }
+func (t *Chan) Chan() *Chan                { return t }
+
+func (t *Named) Named() *Named             { return t }
+func (t *TypeParam) TypeParam() *TypeParam { return t }
+
+// Type-specific implementations of Underlying.
+func (t *Basic) Underlying() Type     { return t }
+func (t *Array) Underlying() Type     { return t }
+func (t *Slice) Underlying() Type     { return t }
+func (t *Struct) Underlying() Type    { return t }
+func (t *Pointer) Underlying() Type   { return t }
+func (t *Tuple) Underlying() Type     { return t }
+func (t *Signature) Underlying() Type { return t }
+func (t *Sum) Underlying() Type       { return t }
+func (t *Interface) Underlying() Type { return t }
+func (t *Map) Underlying() Type       { return t }
+func (t *Chan) Underlying() Type      { return t }
+func (t *Named) Underlying() Type     { return t.underlying }
+func (t *TypeParam) Underlying() Type { return t }
+func (t *instance) Underlying() Type  { return t }
+func (t *bottom) Underlying() Type    { return t }
+func (t *top) Underlying() Type       { return t }
+
+// Type-specific implementations of Under.
+func (t *Basic) Under() Type     { return t }
+func (t *Array) Under() Type     { return t }
+func (t *Slice) Under() Type     { return t }
+func (t *Struct) Under() Type    { return t }
+func (t *Pointer) Under() Type   { return t }
+func (t *Tuple) Under() Type     { return t }
+func (t *Signature) Under() Type { return t }
+func (t *Sum) Under() Type       { return t } // TODO(gri) is this correct?
+func (t *Interface) Under() Type { return t }
+func (t *Map) Under() Type       { return t }
+func (t *Chan) Under() Type      { return t }
+
+// see decl.go for implementation of Named.Under
+func (t *TypeParam) Under() Type { return t }
+func (t *instance) Under() Type  { return t.expand().Under() }
+func (t *bottom) Under() Type    { return t }
+func (t *top) Under() Type       { return t }
+
+// Type-specific implementations of String.
+func (t *Basic) String() string     { return TypeString(t, nil) }
+func (t *Array) String() string     { return TypeString(t, nil) }
+func (t *Slice) String() string     { return TypeString(t, nil) }
+func (t *Struct) String() string    { return TypeString(t, nil) }
+func (t *Pointer) String() string   { return TypeString(t, nil) }
+func (t *Tuple) String() string     { return TypeString(t, nil) }
+func (t *Signature) String() string { return TypeString(t, nil) }
+func (t *Sum) String() string       { return TypeString(t, nil) }
+func (t *Interface) String() string { return TypeString(t, nil) }
+func (t *Map) String() string       { return TypeString(t, nil) }
+func (t *Chan) String() string      { return TypeString(t, nil) }
+func (t *Named) String() string     { return TypeString(t, nil) }
+func (t *TypeParam) String() string { return TypeString(t, nil) }
+func (t *instance) String() string  { return TypeString(t, nil) }
+func (t *bottom) String() string    { return TypeString(t, nil) }
+func (t *top) String() string       { return TypeString(t, nil) }
diff --git a/src/cmd/compile/internal/types2/typestring.go b/src/cmd/compile/internal/types2/typestring.go
new file mode 100644 (file)
index 0000000..6b6d7ad
--- /dev/null
@@ -0,0 +1,477 @@
+// UNREVIEWED
+// Copyright 2013 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.
+
+// This file implements printing of types.
+
+package types2
+
+import (
+       "bytes"
+       "fmt"
+       "unicode/utf8"
+)
+
+// A Qualifier controls how named package-level objects are printed in
+// calls to TypeString, ObjectString, and SelectionString.
+//
+// These three formatting routines call the Qualifier for each
+// package-level object O, and if the Qualifier returns a non-empty
+// string p, the object is printed in the form p.O.
+// If it returns an empty string, only the object name O is printed.
+//
+// Using a nil Qualifier is equivalent to using (*Package).Path: the
+// object is qualified by the import path, e.g., "encoding/json.Marshal".
+//
+type Qualifier func(*Package) string
+
+// RelativeTo returns a Qualifier that fully qualifies members of
+// all packages other than pkg.
+func RelativeTo(pkg *Package) Qualifier {
+       if pkg == nil {
+               return nil
+       }
+       return func(other *Package) string {
+               if pkg == other {
+                       return "" // same package; unqualified
+               }
+               return other.Path()
+       }
+}
+
+// If gcCompatibilityMode is set, printing of types is modified
+// to match the representation of some types in the gc compiler:
+//
+//     - byte and rune lose their alias name and simply stand for
+//       uint8 and int32 respectively
+//     - embedded interfaces get flattened (the embedding info is lost,
+//       and certain recursive interface types cannot be printed anymore)
+//
+// This makes it easier to compare packages computed with the type-
+// checker vs packages imported from gc export data.
+//
+// Caution: This flag affects all uses of WriteType, globally.
+// It is only provided for testing in conjunction with
+// gc-generated data.
+//
+// This flag is exported in the x/tools/go/types package. We don't
+// need it at the moment in the std repo and so we don't export it
+// anymore. We should eventually try to remove it altogether.
+// TODO(gri) remove this
+var gcCompatibilityMode bool
+
+// TypeString returns the string representation of typ.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func TypeString(typ Type, qf Qualifier) string {
+       var buf bytes.Buffer
+       WriteType(&buf, typ, qf)
+       return buf.String()
+}
+
+// WriteType writes the string representation of typ to buf.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
+       writeType(buf, typ, qf, make([]Type, 0, 8))
+}
+
+// instanceMarker is the prefix for an instantiated type
+// in "non-evaluated" instance form.
+const instanceMarker = '#'
+
+func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
+       // Theoretically, this is a quadratic lookup algorithm, but in
+       // practice deeply nested composite types with unnamed component
+       // types are uncommon. This code is likely more efficient than
+       // using a map.
+       for _, t := range visited {
+               if t == typ {
+                       fmt.Fprintf(buf, "○%T", goTypeName(typ)) // cycle to typ
+                       return
+               }
+       }
+       visited = append(visited, typ)
+
+       switch t := typ.(type) {
+       case nil:
+               buf.WriteString("<nil>")
+
+       case *Basic:
+               if t.kind == UnsafePointer {
+                       buf.WriteString("unsafe.")
+               }
+               if gcCompatibilityMode {
+                       // forget the alias names
+                       switch t.kind {
+                       case Byte:
+                               t = Typ[Uint8]
+                       case Rune:
+                               t = Typ[Int32]
+                       }
+               }
+               buf.WriteString(t.name)
+
+       case *Array:
+               fmt.Fprintf(buf, "[%d]", t.len)
+               writeType(buf, t.elem, qf, visited)
+
+       case *Slice:
+               buf.WriteString("[]")
+               writeType(buf, t.elem, qf, visited)
+
+       case *Struct:
+               buf.WriteString("struct{")
+               for i, f := range t.fields {
+                       if i > 0 {
+                               buf.WriteString("; ")
+                       }
+                       buf.WriteString(f.name)
+                       if f.embedded {
+                               // emphasize that the embedded field's name
+                               // doesn't match the field's type name
+                               if f.name != embeddedFieldName(f.typ) {
+                                       buf.WriteString(" /* = ")
+                                       writeType(buf, f.typ, qf, visited)
+                                       buf.WriteString(" */")
+                               }
+                       } else {
+                               buf.WriteByte(' ')
+                               writeType(buf, f.typ, qf, visited)
+                       }
+                       if tag := t.Tag(i); tag != "" {
+                               fmt.Fprintf(buf, " %q", tag)
+                       }
+               }
+               buf.WriteByte('}')
+
+       case *Pointer:
+               buf.WriteByte('*')
+               writeType(buf, t.base, qf, visited)
+
+       case *Tuple:
+               writeTuple(buf, t, false, qf, visited)
+
+       case *Signature:
+               buf.WriteString("func")
+               writeSignature(buf, t, qf, visited)
+
+       case *Sum:
+               for i, t := range t.types {
+                       if i > 0 {
+                               buf.WriteString(", ")
+                       }
+                       writeType(buf, t, qf, visited)
+               }
+
+       case *Interface:
+               // We write the source-level methods and embedded types rather
+               // than the actual method set since resolved method signatures
+               // may have non-printable cycles if parameters have embedded
+               // interface types that (directly or indirectly) embed the
+               // current interface. For instance, consider the result type
+               // of m:
+               //
+               //     type T interface{
+               //         m() interface{ T }
+               //     }
+               //
+               buf.WriteString("interface{")
+               empty := true
+               if gcCompatibilityMode {
+                       // print flattened interface
+                       // (useful to compare against gc-generated interfaces)
+                       for i, m := range t.allMethods {
+                               if i > 0 {
+                                       buf.WriteString("; ")
+                               }
+                               buf.WriteString(m.name)
+                               writeSignature(buf, m.typ.(*Signature), qf, visited)
+                               empty = false
+                       }
+                       if !empty && t.allTypes != nil {
+                               buf.WriteString("; ")
+                       }
+                       if t.allTypes != nil {
+                               buf.WriteString("type ")
+                               writeType(buf, t.allTypes, qf, visited)
+                       }
+               } else {
+                       // print explicit interface methods and embedded types
+                       for i, m := range t.methods {
+                               if i > 0 {
+                                       buf.WriteString("; ")
+                               }
+                               buf.WriteString(m.name)
+                               writeSignature(buf, m.typ.(*Signature), qf, visited)
+                               empty = false
+                       }
+                       if !empty && t.types != nil {
+                               buf.WriteString("; ")
+                       }
+                       if t.types != nil {
+                               buf.WriteString("type ")
+                               writeType(buf, t.types, qf, visited)
+                               empty = false
+                       }
+                       if !empty && len(t.embeddeds) > 0 {
+                               buf.WriteString("; ")
+                       }
+                       for i, typ := range t.embeddeds {
+                               if i > 0 {
+                                       buf.WriteString("; ")
+                               }
+                               writeType(buf, typ, qf, visited)
+                               empty = false
+                       }
+               }
+               if t.allMethods == nil || len(t.methods) > len(t.allMethods) {
+                       if !empty {
+                               buf.WriteByte(' ')
+                       }
+                       buf.WriteString("/* incomplete */")
+               }
+               buf.WriteByte('}')
+
+       case *Map:
+               buf.WriteString("map[")
+               writeType(buf, t.key, qf, visited)
+               buf.WriteByte(']')
+               writeType(buf, t.elem, qf, visited)
+
+       case *Chan:
+               var s string
+               var parens bool
+               switch t.dir {
+               case SendRecv:
+                       s = "chan "
+                       // chan (<-chan T) requires parentheses
+                       if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
+                               parens = true
+                       }
+               case SendOnly:
+                       s = "chan<- "
+               case RecvOnly:
+                       s = "<-chan "
+               default:
+                       panic("unreachable")
+               }
+               buf.WriteString(s)
+               if parens {
+                       buf.WriteByte('(')
+               }
+               writeType(buf, t.elem, qf, visited)
+               if parens {
+                       buf.WriteByte(')')
+               }
+
+       case *Named:
+               writeTypeName(buf, t.obj, qf)
+               if t.targs != nil {
+                       // instantiated type
+                       buf.WriteByte('[')
+                       writeTypeList(buf, t.targs, qf, visited)
+                       buf.WriteByte(']')
+               } else if t.tparams != nil {
+                       // parameterized type
+                       writeTParamList(buf, t.tparams, qf, visited)
+               }
+
+       case *TypeParam:
+               s := "?"
+               if t.obj != nil {
+                       s = t.obj.name
+               }
+               buf.WriteString(s + subscript(t.id))
+
+       case *instance:
+               buf.WriteByte(instanceMarker) // indicate "non-evaluated" syntactic instance
+               writeTypeName(buf, t.base.obj, qf)
+               buf.WriteByte('[')
+               writeTypeList(buf, t.targs, qf, visited)
+               buf.WriteByte(']')
+
+       case *bottom:
+               buf.WriteString("⊥")
+
+       case *top:
+               buf.WriteString("⊤")
+
+       default:
+               // For externally defined implementations of Type.
+               buf.WriteString(t.String())
+       }
+}
+
+func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
+       for i, typ := range list {
+               if i > 0 {
+                       buf.WriteString(", ")
+               }
+               writeType(buf, typ, qf, visited)
+       }
+}
+
+func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
+       // bound returns the type bound for tname. The result is never nil.
+       bound := func(tname *TypeName) Type {
+               // be careful to avoid crashes in case of inconsistencies
+               if t, _ := tname.typ.(*TypeParam); t != nil && t.bound != nil {
+                       return t.bound
+               }
+               return &emptyInterface
+       }
+
+       // If a single type bound is not the empty interface, we have to write them all.
+       var writeBounds bool
+       for _, p := range list {
+               // bound(p) should be an interface but be careful (it may be invalid)
+               b := bound(p).Interface()
+               if b != nil && !b.Empty() {
+                       writeBounds = true
+                       break
+               }
+       }
+       writeBounds = true // always write the bounds for new type parameter list syntax
+
+       buf.WriteString("[")
+       var prev Type
+       for i, p := range list {
+               b := bound(p)
+               if i > 0 {
+                       if writeBounds && b != prev {
+                               // type bound changed - write previous one before advancing
+                               buf.WriteByte(' ')
+                               writeType(buf, prev, qf, visited)
+                       }
+                       buf.WriteString(", ")
+               }
+               prev = b
+
+               if t, _ := p.typ.(*TypeParam); t != nil {
+                       writeType(buf, t, qf, visited)
+               } else {
+                       buf.WriteString(p.name)
+               }
+       }
+       if writeBounds && prev != nil {
+               buf.WriteByte(' ')
+               writeType(buf, prev, qf, visited)
+       }
+       buf.WriteByte(']')
+}
+
+func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
+       s := "<Named w/o object>"
+       if obj != nil {
+               if obj.pkg != nil {
+                       writePackage(buf, obj.pkg, qf)
+               }
+               // TODO(gri): function-local named types should be displayed
+               // differently from named types at package level to avoid
+               // ambiguity.
+               s = obj.name
+       }
+       buf.WriteString(s)
+}
+
+func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
+       buf.WriteByte('(')
+       if tup != nil {
+               for i, v := range tup.vars {
+                       if i > 0 {
+                               buf.WriteString(", ")
+                       }
+                       if v.name != "" {
+                               buf.WriteString(v.name)
+                               buf.WriteByte(' ')
+                       }
+                       typ := v.typ
+                       if variadic && i == len(tup.vars)-1 {
+                               if s, ok := typ.(*Slice); ok {
+                                       buf.WriteString("...")
+                                       typ = s.elem
+                               } else {
+                                       // special case:
+                                       // append(s, "foo"...) leads to signature func([]byte, string...)
+                                       if t := typ.Basic(); t == nil || t.kind != String {
+                                               panic("internal error: string type expected")
+                                       }
+                                       writeType(buf, typ, qf, visited)
+                                       buf.WriteString("...")
+                                       continue
+                               }
+                       }
+                       writeType(buf, typ, qf, visited)
+               }
+       }
+       buf.WriteByte(')')
+}
+
+// WriteSignature writes the representation of the signature sig to buf,
+// without a leading "func" keyword.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
+       writeSignature(buf, sig, qf, make([]Type, 0, 8))
+}
+
+func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
+       if sig.tparams != nil {
+               writeTParamList(buf, sig.tparams, qf, visited)
+       }
+
+       writeTuple(buf, sig.params, sig.variadic, qf, visited)
+
+       n := sig.results.Len()
+       if n == 0 {
+               // no result
+               return
+       }
+
+       buf.WriteByte(' ')
+       if n == 1 && sig.results.vars[0].name == "" {
+               // single unnamed result
+               writeType(buf, sig.results.vars[0].typ, qf, visited)
+               return
+       }
+
+       // multiple or named result(s)
+       writeTuple(buf, sig.results, false, qf, visited)
+}
+
+// embeddedFieldName returns an embedded field's name given its type.
+// The result is "" if the type doesn't have an embedded field name.
+func embeddedFieldName(typ Type) string {
+       switch t := typ.(type) {
+       case *Basic:
+               return t.name
+       case *Named:
+               return t.obj.name
+       case *Pointer:
+               // *T is ok, but **T is not
+               if _, ok := t.base.(*Pointer); !ok {
+                       return embeddedFieldName(t.base)
+               }
+       case *instance:
+               return t.base.obj.name
+       }
+       return "" // not a (pointer to) a defined type
+}
+
+// subscript returns the decimal (utf8) representation of x using subscript digits.
+func subscript(x uint64) string {
+       const w = len("₀") // all digits 0...9 have the same utf8 width
+       var buf [32 * w]byte
+       i := len(buf)
+       for {
+               i -= w
+               utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
+               x /= 10
+               if x == 0 {
+                       break
+               }
+       }
+       return string(buf[i:])
+}
diff --git a/src/cmd/compile/internal/types2/typestring_test.go b/src/cmd/compile/internal/types2/typestring_test.go
new file mode 100644 (file)
index 0000000..f1f7e34
--- /dev/null
@@ -0,0 +1,221 @@
+// UNREVIEWED
+// Copyright 2012 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 (
+       "internal/testenv"
+       "testing"
+
+       "cmd/compile/internal/syntax"
+       . "cmd/compile/internal/types2"
+)
+
+const filename = "<src>"
+
+func makePkg(src string) (*Package, error) {
+       file, err := parseSrc(filename, src)
+       if err != nil {
+               return nil, err
+       }
+       // use the package name as package path
+       conf := Config{Importer: defaultImporter()}
+       return conf.Check(file.PkgName.Value, []*syntax.File{file}, nil)
+}
+
+type testEntry struct {
+       src, str string
+}
+
+// dup returns a testEntry where both src and str are the same.
+func dup(s string) testEntry {
+       return testEntry{s, s}
+}
+
+// types that don't depend on any other type declarations
+var independentTestTypes = []testEntry{
+       // basic types
+       dup("int"),
+       dup("float32"),
+       dup("string"),
+
+       // arrays
+       dup("[10]int"),
+
+       // slices
+       dup("[]int"),
+       dup("[][]int"),
+
+       // structs
+       dup("struct{}"),
+       dup("struct{x int}"),
+       {`struct {
+               x, y int
+               z float32 "foo"
+       }`, `struct{x int; y int; z float32 "foo"}`},
+       {`struct {
+               string
+               elems []complex128
+       }`, `struct{string; elems []complex128}`},
+
+       // pointers
+       dup("*int"),
+       dup("***struct{}"),
+       dup("*struct{a int; b float32}"),
+
+       // functions
+       dup("func()"),
+       dup("func(x int)"),
+       {"func(x, y int)", "func(x int, y int)"},
+       {"func(x, y int, z string)", "func(x int, y int, z string)"},
+       dup("func(int)"),
+       {"func(int, string, byte)", "func(int, string, byte)"},
+
+       dup("func() int"),
+       {"func() (string)", "func() string"},
+       dup("func() (u int)"),
+       {"func() (u, v int, w string)", "func() (u int, v int, w string)"},
+
+       dup("func(int) string"),
+       dup("func(x int) string"),
+       dup("func(x int) (u string)"),
+       {"func(x, y int) (u string)", "func(x int, y int) (u string)"},
+
+       dup("func(...int) string"),
+       dup("func(x ...int) string"),
+       dup("func(x ...int) (u string)"),
+       {"func(x int, y ...int) (u string)", "func(x int, y ...int) (u string)"},
+
+       // interfaces
+       dup("interface{}"),
+       dup("interface{m()}"),
+       dup(`interface{String() string; m(int) float32}`),
+       dup(`interface{type int, float32, complex128}`),
+
+       // maps
+       dup("map[string]int"),
+       {"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},
+
+       // channels
+       dup("chan<- chan int"),
+       dup("chan<- <-chan int"),
+       dup("<-chan <-chan int"),
+       dup("chan (<-chan int)"),
+       dup("chan<- func()"),
+       dup("<-chan []func() int"),
+}
+
+// types that depend on other type declarations (src in TestTypes)
+var dependentTestTypes = []testEntry{
+       // interfaces
+       dup(`interface{io.Reader; io.Writer}`),
+       dup(`interface{m() int; io.Writer}`),
+       {`interface{m() interface{T}}`, `interface{m() interface{p.T}}`},
+}
+
+func TestTypeString(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       var tests []testEntry
+       tests = append(tests, independentTestTypes...)
+       tests = append(tests, dependentTestTypes...)
+
+       for _, test := range tests {
+               src := `package p; import "io"; type _ io.Writer; type T ` + test.src
+               pkg, err := makePkg(src)
+               if err != nil {
+                       t.Errorf("%s: %s", src, err)
+                       continue
+               }
+               typ := pkg.Scope().Lookup("T").Type().Underlying()
+               if got := typ.String(); got != test.str {
+                       t.Errorf("%s: got %s, want %s", test.src, got, test.str)
+               }
+       }
+}
+
+var nopos syntax.Pos
+
+func TestIncompleteInterfaces(t *testing.T) {
+       sig := NewSignature(nil, nil, nil, false)
+       m := NewFunc(nopos, nil, "m", sig)
+       for _, test := range []struct {
+               typ  *Interface
+               want string
+       }{
+               {new(Interface), "interface{/* incomplete */}"},
+               {new(Interface).Complete(), "interface{}"},
+
+               {NewInterface(nil, nil), "interface{}"},
+               {NewInterface(nil, nil).Complete(), "interface{}"},
+               {NewInterface([]*Func{}, nil), "interface{}"},
+               {NewInterface([]*Func{}, nil).Complete(), "interface{}"},
+               {NewInterface(nil, []*Named{}), "interface{}"},
+               {NewInterface(nil, []*Named{}).Complete(), "interface{}"},
+               {NewInterface([]*Func{m}, nil), "interface{m() /* incomplete */}"},
+               {NewInterface([]*Func{m}, nil).Complete(), "interface{m()}"},
+               {NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}), "interface{T /* incomplete */}"},
+               {NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}).Complete(), "interface{T}"},
+               {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil))}), "interface{T /* incomplete */}"},
+               {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}), "interface{T /* incomplete */}"},
+               {NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}).Complete(), "interface{T}"},
+
+               {NewInterfaceType(nil, nil), "interface{}"},
+               {NewInterfaceType(nil, nil).Complete(), "interface{}"},
+               {NewInterfaceType([]*Func{}, nil), "interface{}"},
+               {NewInterfaceType([]*Func{}, nil).Complete(), "interface{}"},
+               {NewInterfaceType(nil, []Type{}), "interface{}"},
+               {NewInterfaceType(nil, []Type{}).Complete(), "interface{}"},
+               {NewInterfaceType([]*Func{m}, nil), "interface{m() /* incomplete */}"},
+               {NewInterfaceType([]*Func{m}, nil).Complete(), "interface{m()}"},
+               {NewInterfaceType(nil, []Type{new(Interface).Complete()}), "interface{interface{} /* incomplete */}"},
+               {NewInterfaceType(nil, []Type{new(Interface).Complete()}).Complete(), "interface{interface{}}"},
+               {NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil)}), "interface{interface{m() /* incomplete */} /* incomplete */}"},
+               {NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil).Complete()}), "interface{interface{m()} /* incomplete */}"},
+               {NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil).Complete()}).Complete(), "interface{interface{m()}}"},
+       } {
+               got := test.typ.String()
+               if got != test.want {
+                       t.Errorf("got: %s, want: %s", got, test.want)
+               }
+       }
+}
+
+// newDefined creates a new defined type named T with the given underlying type.
+// Helper function for use with TestIncompleteInterfaces only.
+func newDefined(underlying Type) *Named {
+       tname := NewTypeName(nopos, nil, "T", nil)
+       return NewNamed(tname, underlying, nil)
+}
+
+func TestQualifiedTypeString(t *testing.T) {
+       p, _ := pkgFor("p.go", "package p; type T int", nil)
+       q, _ := pkgFor("q.go", "package q", nil)
+
+       pT := p.Scope().Lookup("T").Type()
+       for _, test := range []struct {
+               typ  Type
+               this *Package
+               want string
+       }{
+               {nil, nil, "<nil>"},
+               {pT, nil, "p.T"},
+               {pT, p, "T"},
+               {pT, q, "p.T"},
+               {NewPointer(pT), p, "*T"},
+               {NewPointer(pT), q, "*p.T"},
+       } {
+               qualifier := func(pkg *Package) string {
+                       if pkg != test.this {
+                               return pkg.Name()
+                       }
+                       return ""
+               }
+               if got := TypeString(test.typ, qualifier); got != test.want {
+                       t.Errorf("TypeString(%s, %s) = %s, want %s",
+                               test.this, test.typ, got, test.want)
+               }
+       }
+}
diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go
new file mode 100644 (file)
index 0000000..4231577
--- /dev/null
@@ -0,0 +1,1298 @@
+// UNREVIEWED
+// Copyright 2013 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.
+
+// This file implements type-checking of identifiers and type expressions.
+
+package types2
+
+import (
+       "cmd/compile/internal/syntax"
+       "fmt"
+       "go/constant"
+       "sort"
+       "strconv"
+       "strings"
+)
+
+// ident type-checks identifier e and initializes x with the value or type of e.
+// If an error occurred, x.mode is set to invalid.
+// For the meaning of def, see Checker.definedType, below.
+// If wantType is set, the identifier e is expected to denote a type.
+//
+func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType bool) {
+       x.mode = invalid
+       x.expr = e
+
+       // Note that we cannot use check.lookup here because the returned scope
+       // may be different from obj.Parent(). See also Scope.LookupParent doc.
+       scope, obj := check.scope.LookupParent(e.Value, check.pos)
+       if obj == nil {
+               if e.Value == "_" {
+                       check.errorf(e, "cannot use _ as value or type")
+               } else {
+                       if check.conf.CompilerErrorMessages {
+                               check.errorf(e, "undefined: %s", e.Value)
+                       } else {
+                               check.errorf(e, "undeclared name: %s", e.Value)
+                       }
+               }
+               return
+       }
+       check.recordUse(e, obj)
+
+       // Type-check the object.
+       // Only call Checker.objDecl if the object doesn't have a type yet
+       // (in which case we must actually determine it) or the object is a
+       // TypeName and we also want a type (in which case we might detect
+       // a cycle which needs to be reported). Otherwise we can skip the
+       // call and avoid a possible cycle error in favor of the more
+       // informative "not a type/value" error that this function's caller
+       // will issue (see issue #25790).
+       typ := obj.Type()
+       if _, gotType := obj.(*TypeName); typ == nil || gotType && wantType {
+               check.objDecl(obj, def)
+               typ = obj.Type() // type must have been assigned by Checker.objDecl
+       }
+       assert(typ != nil)
+
+       // The object may be dot-imported: If so, remove its package from
+       // the map of unused dot imports for the respective file scope.
+       // (This code is only needed for dot-imports. Without them,
+       // we only have to mark variables, see *Var case below).
+       if pkg := obj.Pkg(); pkg != check.pkg && pkg != nil {
+               delete(check.unusedDotImports[scope], pkg)
+       }
+
+       switch obj := obj.(type) {
+       case *PkgName:
+               check.errorf(e, "use of package %s not in selector", obj.name)
+               return
+
+       case *Const:
+               check.addDeclDep(obj)
+               if typ == Typ[Invalid] {
+                       return
+               }
+               if obj == universeIota {
+                       if check.iota == nil {
+                               check.errorf(e, "cannot use iota outside constant declaration")
+                               return
+                       }
+                       x.val = check.iota
+               } else {
+                       x.val = obj.val
+               }
+               assert(x.val != nil)
+               x.mode = constant_
+
+       case *TypeName:
+               x.mode = typexpr
+
+       case *Var:
+               // It's ok to mark non-local variables, but ignore variables
+               // from other packages to avoid potential race conditions with
+               // dot-imported variables.
+               if obj.pkg == check.pkg {
+                       obj.used = true
+               }
+               check.addDeclDep(obj)
+               if typ == Typ[Invalid] {
+                       return
+               }
+               x.mode = variable
+
+       case *Func:
+               check.addDeclDep(obj)
+               x.mode = value
+
+       case *Builtin:
+               x.id = obj.id
+               x.mode = builtin
+
+       case *Nil:
+               x.mode = value
+
+       default:
+               unreachable()
+       }
+
+       x.typ = typ
+}
+
+// typ type-checks the type expression e and returns its type, or Typ[Invalid].
+// The type must not be an (uninstantiated) generic type.
+func (check *Checker) typ(e syntax.Expr) Type {
+       return check.definedType(e, nil)
+}
+
+// varType type-checks the type expression e and returns its type, or Typ[Invalid].
+// The type must not be an (uninstantiated) generic type and it must be ordinary
+// (see ordinaryType).
+func (check *Checker) varType(e syntax.Expr) Type {
+       typ := check.definedType(e, nil)
+       check.ordinaryType(startPos(e), typ)
+       return typ
+}
+
+// ordinaryType reports an error if typ is an interface type containing
+// type lists or is (or embeds) the predeclared type comparable.
+func (check *Checker) ordinaryType(pos syntax.Pos, typ Type) {
+       // We don't want to call Under() (via Interface) or complete interfaces while we
+       // are in the middle of type-checking parameter declarations that might belong to
+       // interface methods. Delay this check to the end of type-checking.
+       check.atEnd(func() {
+               if t := typ.Interface(); t != nil {
+                       check.completeInterface(pos, t) // TODO(gri) is this the correct position?
+                       if t.allTypes != nil {
+                               check.softErrorf(pos, "interface contains type constraints (%s)", t.allTypes)
+                               return
+                       }
+                       if t.IsComparable() {
+                               check.softErrorf(pos, "interface is (or embeds) comparable")
+                       }
+               }
+       })
+}
+
+// anyType type-checks the type expression e and returns its type, or Typ[Invalid].
+// The type may be generic or instantiated.
+func (check *Checker) anyType(e syntax.Expr) Type {
+       typ := check.typInternal(e, nil)
+       assert(isTyped(typ))
+       check.recordTypeAndValue(e, typexpr, typ, nil)
+       return typ
+}
+
+// definedType is like typ but also accepts a type name def.
+// If def != nil, e is the type specification for the defined type def, declared
+// in a type declaration, and def.underlying will be set to the type of e before
+// any components of e are type-checked.
+//
+func (check *Checker) definedType(e syntax.Expr, def *Named) Type {
+       typ := check.typInternal(e, def)
+       assert(isTyped(typ))
+       if isGeneric(typ) {
+               check.errorf(e, "cannot use generic type %s without instantiation", typ)
+               typ = Typ[Invalid]
+       }
+       check.recordTypeAndValue(e, typexpr, typ, nil)
+       return typ
+}
+
+// genericType is like typ but the type must be an (uninstantiated) generic type.
+func (check *Checker) genericType(e syntax.Expr, reportErr bool) Type {
+       typ := check.typInternal(e, nil)
+       assert(isTyped(typ))
+       if typ != Typ[Invalid] && !isGeneric(typ) {
+               if reportErr {
+                       check.errorf(e, "%s is not a generic type", typ)
+               }
+               typ = Typ[Invalid]
+       }
+       // TODO(gri) what is the correct call below?
+       check.recordTypeAndValue(e, typexpr, typ, nil)
+       return typ
+}
+
+// isubst returns an x with identifiers substituted per the substitution map smap.
+// isubst only handles the case of (valid) method receiver type expressions correctly.
+func isubst(x syntax.Expr, smap map[*syntax.Name]*syntax.Name) syntax.Expr {
+       switch n := x.(type) {
+       case *syntax.Name:
+               if alt := smap[n]; alt != nil {
+                       return alt
+               }
+       // case *syntax.StarExpr:
+       //      X := isubst(n.X, smap)
+       //      if X != n.X {
+       //              new := *n
+       //              new.X = X
+       //              return &new
+       //      }
+       case *syntax.Operation:
+               if n.Op == syntax.Mul && n.Y == nil {
+                       X := isubst(n.X, smap)
+                       if X != n.X {
+                               new := *n
+                               new.X = X
+                               return &new
+                       }
+               }
+       case *syntax.IndexExpr:
+               Index := isubst(n.Index, smap)
+               if Index != n.Index {
+                       new := *n
+                       new.Index = Index
+                       return &new
+               }
+       case *syntax.ListExpr:
+               var elems []syntax.Expr
+               for i, elem := range n.ElemList {
+                       Elem := isubst(elem, smap)
+                       if Elem != elem {
+                               if elems == nil {
+                                       elems = make([]syntax.Expr, len(n.ElemList))
+                                       copy(elems, n.ElemList)
+                               }
+                               elems[i] = Elem
+                       }
+               }
+               if elems != nil {
+                       new := *n
+                       new.ElemList = elems
+                       return &new
+               }
+       case *syntax.ParenExpr:
+               return isubst(n.X, smap) // no need to keep parentheses
+       default:
+               // Other receiver type expressions are invalid.
+               // It's fine to ignore those here as they will
+               // be checked elsewhere.
+       }
+       return x
+}
+
+// funcType type-checks a function or method type.
+func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []*syntax.Field, ftyp *syntax.FuncType) {
+       check.openScope(ftyp, "function")
+       check.scope.isFunc = true
+       check.recordScope(ftyp, check.scope)
+       sig.scope = check.scope
+       defer check.closeScope()
+
+       var recvTyp syntax.Expr // rewritten receiver type; valid if != nil
+       if recvPar != nil {
+               // collect generic receiver type parameters, if any
+               // - a receiver type parameter is like any other type parameter, except that it is declared implicitly
+               // - the receiver specification acts as local declaration for its type parameters, which may be blank
+               _, rname, rparams := check.unpackRecv(recvPar.Type, true)
+               if len(rparams) > 0 {
+                       // Blank identifiers don't get declared and regular type-checking of the instantiated
+                       // parameterized receiver type expression fails in Checker.collectParams of receiver.
+                       // Identify blank type parameters and substitute each with a unique new identifier named
+                       // "n_" (where n is the parameter index) and which cannot conflict with any user-defined
+                       // name.
+                       var smap map[*syntax.Name]*syntax.Name // substitution map from "_" to "!n" identifiers
+                       for i, p := range rparams {
+                               if p.Value == "_" {
+                                       new := *p
+                                       new.Value = fmt.Sprintf("%d_", i)
+                                       rparams[i] = &new // use n_ identifier instead of _ so it can be looked up
+                                       if smap == nil {
+                                               smap = make(map[*syntax.Name]*syntax.Name)
+                                       }
+                                       smap[p] = &new
+                               }
+                       }
+                       if smap != nil {
+                               // blank identifiers were found => use rewritten receiver type
+                               recvTyp = isubst(recvPar.Type, smap)
+                       }
+                       // TODO(gri) rework declareTypeParams
+                       sig.rparams = nil
+                       for _, rparam := range rparams {
+                               sig.rparams = check.declareTypeParam(sig.rparams, rparam)
+                       }
+                       // determine receiver type to get its type parameters
+                       // and the respective type parameter bounds
+                       var recvTParams []*TypeName
+                       if rname != nil {
+                               // recv should be a Named type (otherwise an error is reported elsewhere)
+                               // Also: Don't report an error via genericType since it will be reported
+                               //       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
+                               }
+                       }
+                       // provide type parameter bounds
+                       // - only do this if we have the right number (otherwise an error is reported elsewhere)
+                       if len(sig.rparams) == len(recvTParams) {
+                               // We have a list of *TypeNames but we need a list of Types.
+                               list := make([]Type, len(sig.rparams))
+                               for i, t := range sig.rparams {
+                                       list[i] = t.typ
+                               }
+                               for i, tname := range sig.rparams {
+                                       bound := recvTParams[i].typ.(*TypeParam).bound
+                                       // bound is (possibly) parameterized in the context of the
+                                       // receiver type declaration. Substitute parameters for the
+                                       // current context.
+                                       // TODO(gri) should we assume now that bounds always exist?
+                                       //           (no bound == empty interface)
+                                       if bound != nil {
+                                               bound = check.subst(tname.pos, bound, makeSubstMap(recvTParams, list))
+                                               tname.typ.(*TypeParam).bound = bound
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if tparams != nil {
+               sig.tparams = check.collectTypeParams(tparams)
+               // Always type-check method type parameters but complain if they are not enabled.
+               // (A separate check is needed when type-checking interface method signatures because
+               // they don't have a receiver specification.)
+               if recvPar != nil && !check.conf.AcceptMethodTypeParams {
+                       check.errorf(ftyp, "methods cannot have type parameters")
+               }
+       }
+
+       // Value (non-type) parameters' scope starts in the function body. Use a temporary scope for their
+       // declarations and then squash that scope into the parent scope (and report any redeclarations at
+       // that time).
+       scope := NewScope(check.scope, nopos, nopos, "function body (temp. scope)")
+       var recvList []*Var // TODO(gri) remove the need for making a list here
+       if recvPar != nil {
+               recvList, _ = check.collectParams(scope, []*syntax.Field{recvPar}, recvTyp, false) // use rewritten receiver type, if any
+       }
+       params, variadic := check.collectParams(scope, ftyp.ParamList, nil, true)
+       results, _ := check.collectParams(scope, ftyp.ResultList, nil, false)
+       scope.Squash(func(obj, alt Object) {
+               check.errorf(obj, "%s redeclared in this block", obj.Name())
+               check.reportAltDecl(alt)
+       })
+
+       if recvPar != nil {
+               // recv parameter list present (may be empty)
+               // spec: "The receiver is specified via an extra parameter section preceding the
+               // method name. That parameter section must declare a single parameter, the receiver."
+               var recv *Var
+               switch len(recvList) {
+               case 0:
+                       // error reported by resolver
+                       recv = NewParam(nopos, nil, "", Typ[Invalid]) // ignore recv below
+               default:
+                       // more than one receiver
+                       check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver")
+                       fallthrough // continue with first receiver
+               case 1:
+                       recv = recvList[0]
+               }
+
+               // TODO(gri) We should delay rtyp expansion to when we actually need the
+               //           receiver; thus all checks here should be delayed to later.
+               rtyp, _ := deref(recv.typ)
+               rtyp = expand(rtyp)
+
+               // spec: "The receiver type must be of the form T or *T where T is a type name."
+               // (ignore invalid types - error was reported before)
+               if t := rtyp; t != Typ[Invalid] {
+                       var err string
+                       if T := t.Named(); T != nil {
+                               // spec: "The type denoted by T is called the receiver base type; it must not
+                               // be a pointer or interface type and it must be declared in the same package
+                               // as the method."
+                               if T.obj.pkg != check.pkg {
+                                       err = "type not defined in this package"
+                                       if check.conf.CompilerErrorMessages {
+                                               check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
+                                               err = ""
+                                       }
+                               } else {
+                                       switch u := optype(T.Under()).(type) {
+                                       case *Basic:
+                                               // unsafe.Pointer is treated like a regular pointer
+                                               if u.kind == UnsafePointer {
+                                                       err = "unsafe.Pointer"
+                                               }
+                                       case *Pointer, *Interface:
+                                               err = "pointer or interface type"
+                                       }
+                               }
+                       } else if T := t.Basic(); T != nil {
+                               err = "basic or unnamed type"
+                               if check.conf.CompilerErrorMessages {
+                                       check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
+                                       err = ""
+                               }
+                       } else {
+                               check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
+                       }
+                       if err != "" {
+                               check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
+                               // ok to continue
+                       }
+               }
+               sig.recv = recv
+       }
+
+       sig.params = NewTuple(params...)
+       sig.results = NewTuple(results...)
+       sig.variadic = variadic
+}
+
+// goTypeName returns the Go type name for typ and
+// removes any occurences of "types." from that name.
+func goTypeName(typ Type) string {
+       return strings.Replace(fmt.Sprintf("%T", typ), "types.", "", -1) // strings.ReplaceAll is not available in Go 1.4
+}
+
+// typInternal drives type checking of types.
+// Must only be called by definedType or genericType.
+//
+func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
+       if check.conf.Trace {
+               check.trace(e0.Pos(), "type %s", e0)
+               check.indent++
+               defer func() {
+                       check.indent--
+                       var under Type
+                       if T != nil {
+                               // Calling Under() here may lead to endless instantiations.
+                               // Test case: type T[P any] *T[P]
+                               // TODO(gri) investigate if that's a bug or to be expected
+                               // (see also analogous comment in Checker.instantiate).
+                               under = T.Underlying()
+                       }
+                       if T == under {
+                               check.trace(e0.Pos(), "=> %s // %s", T, goTypeName(T))
+                       } else {
+                               check.trace(e0.Pos(), "=> %s (under = %s) // %s", T, under, goTypeName(T))
+                       }
+               }()
+       }
+
+       switch e := e0.(type) {
+       case *syntax.BadExpr:
+               // ignore - error reported before
+
+       case *syntax.Name:
+               var x operand
+               check.ident(&x, e, def, true)
+
+               switch x.mode {
+               case typexpr:
+                       typ := x.typ
+                       def.setUnderlying(typ)
+                       return typ
+               case invalid:
+                       // ignore - error reported before
+               case novalue:
+                       check.errorf(&x, "%s used as type", &x)
+               default:
+                       check.errorf(&x, "%s is not a type", &x)
+               }
+
+       case *syntax.SelectorExpr:
+               var x operand
+               check.selector(&x, e)
+
+               switch x.mode {
+               case typexpr:
+                       typ := x.typ
+                       def.setUnderlying(typ)
+                       return typ
+               case invalid:
+                       // ignore - error reported before
+               case novalue:
+                       check.errorf(&x, "%s used as type", &x)
+               default:
+                       check.errorf(&x, "%s is not a type", &x)
+               }
+
+       case *syntax.IndexExpr:
+               return check.instantiatedType(e.X, unpackExpr(e.Index), def)
+
+       case *syntax.ParenExpr:
+               // Generic types must be instantiated before they can be used in any form.
+               // Consequently, generic types cannot be parenthesized.
+               return check.definedType(e.X, def)
+
+       case *syntax.ArrayType:
+               typ := new(Array)
+               def.setUnderlying(typ)
+               if e.Len != nil {
+                       typ.len = check.arrayLength(e.Len)
+               } else {
+                       // [...]array
+                       check.errorf(e, "invalid use of [...] array (outside a composite literal)")
+                       typ.len = -1
+               }
+               typ.elem = check.varType(e.Elem)
+               return typ
+
+       case *syntax.SliceType:
+               typ := new(Slice)
+               def.setUnderlying(typ)
+               typ.elem = check.varType(e.Elem)
+               return typ
+
+       case *syntax.StructType:
+               typ := new(Struct)
+               def.setUnderlying(typ)
+               check.structType(typ, e)
+               return typ
+
+       case *syntax.Operation:
+               if e.Op == syntax.Mul && e.Y == nil {
+                       typ := new(Pointer)
+                       def.setUnderlying(typ)
+                       typ.base = check.varType(e.X)
+                       return typ
+               }
+
+               check.errorf(e0, "%s is not a type", e0)
+               check.use(e0)
+
+       case *syntax.FuncType:
+               typ := new(Signature)
+               def.setUnderlying(typ)
+               check.funcType(typ, nil, nil, e)
+               return typ
+
+       case *syntax.InterfaceType:
+               typ := new(Interface)
+               def.setUnderlying(typ)
+               if def != nil {
+                       typ.obj = def.obj
+               }
+               check.interfaceType(typ, e, def)
+               return typ
+
+       case *syntax.MapType:
+               typ := new(Map)
+               def.setUnderlying(typ)
+
+               typ.key = check.varType(e.Key)
+               typ.elem = check.varType(e.Value)
+
+               // spec: "The comparison operators == and != must be fully defined
+               // for operands of the key type; thus the key type must not be a
+               // function, map, or slice."
+               //
+               // Delay this check because it requires fully setup types;
+               // it is safe to continue in any case (was issue 6667).
+               check.atEnd(func() {
+                       if !Comparable(typ.key) {
+                               var why string
+                               if typ.key.TypeParam() != nil {
+                                       why = " (missing comparable constraint)"
+                               }
+                               check.errorf(e.Key, "invalid map key type %s%s", typ.key, why)
+                       }
+               })
+
+               return typ
+
+       case *syntax.ChanType:
+               typ := new(Chan)
+               def.setUnderlying(typ)
+
+               dir := SendRecv
+               switch e.Dir {
+               case 0:
+                       // nothing to do
+               case syntax.SendOnly:
+                       dir = SendOnly
+               case syntax.RecvOnly:
+                       dir = RecvOnly
+               default:
+                       check.invalidASTf(e, "unknown channel direction %d", e.Dir)
+                       // ok to continue
+               }
+
+               typ.dir = dir
+               typ.elem = check.varType(e.Elem)
+               return typ
+
+       default:
+               check.errorf(e0, "%s is not a type", e0)
+               check.use(e0)
+       }
+
+       typ := Typ[Invalid]
+       def.setUnderlying(typ)
+       return typ
+}
+
+// typeOrNil type-checks the type expression (or nil value) e
+// and returns the type of e, or nil. If e is a type, it must
+// not be an (uninstantiated) generic type.
+// If e is neither a type nor nil, typeOrNil returns Typ[Invalid].
+// TODO(gri) should we also disallow non-var types?
+func (check *Checker) typOrNil(e syntax.Expr) Type {
+       var x operand
+       check.rawExpr(&x, e, nil)
+       switch x.mode {
+       case invalid:
+               // ignore - error reported before
+       case novalue:
+               check.errorf(&x, "%s used as type", &x)
+       case typexpr:
+               check.instantiatedOperand(&x)
+               return x.typ
+       case value:
+               if x.isNil() {
+                       return nil
+               }
+               fallthrough
+       default:
+               check.errorf(&x, "%s is not a type", &x)
+       }
+       return Typ[Invalid]
+}
+
+func (check *Checker) instantiatedType(x syntax.Expr, targs []syntax.Expr, def *Named) Type {
+       b := check.genericType(x, true) // TODO(gri) what about cycles?
+       if b == Typ[Invalid] {
+               return b // error already reported
+       }
+       base := b.Named()
+       if base == nil {
+               unreachable() // should have been caught by genericType
+       }
+
+       // create a new type Instance rather than instantiate the type
+       // TODO(gri) should do argument number check here rather than
+       // when instantiating the type?
+       typ := new(instance)
+       def.setUnderlying(typ)
+
+       typ.check = check
+       typ.pos = x.Pos()
+       typ.base = base
+
+       // evaluate arguments (always)
+       typ.targs = check.typeList(targs)
+       if typ.targs == nil {
+               def.setUnderlying(Typ[Invalid]) // avoid later errors due to lazy instantiation
+               return Typ[Invalid]
+       }
+
+       // determine argument positions (for error reporting)
+       typ.poslist = make([]syntax.Pos, len(targs))
+       for i, arg := range targs {
+               typ.poslist[i] = arg.Pos()
+       }
+
+       // make sure we check instantiation works at least once
+       // and that the resulting type is valid
+       check.atEnd(func() {
+               t := typ.expand()
+               check.validType(t, nil)
+       })
+
+       return typ
+}
+
+// arrayLength type-checks the array length expression e
+// 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 {
+       var x operand
+       check.expr(&x, e)
+       if x.mode != constant_ {
+               if x.mode != invalid {
+                       check.errorf(&x, "array length %s must be constant", &x)
+               }
+               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) {
+                               if n, ok := constant.Int64Val(val); ok && n >= 0 {
+                                       return n
+                               }
+                               check.errorf(&x, "invalid array length %s", &x)
+                               return -1
+                       }
+               }
+       }
+       check.errorf(&x, "array length %s must be integer", &x)
+       return -1
+}
+
+// typeList provides the list of types corresponding to the incoming expression list.
+// If an error occured, the result is nil, but all list elements were type-checked.
+func (check *Checker) typeList(list []syntax.Expr) []Type {
+       res := make([]Type, len(list)) // res != nil even if len(list) == 0
+       for i, x := range list {
+               t := check.varType(x)
+               if t == Typ[Invalid] {
+                       res = nil
+               }
+               if res != nil {
+                       res[i] = t
+               }
+       }
+       return res
+}
+
+// collectParams declares the parameters of list in scope and returns the corresponding
+// variable list. If type0 != nil, it is used instead of the first type in list.
+func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 syntax.Expr, variadicOk bool) (params []*Var, variadic bool) {
+       if list == nil {
+               return
+       }
+
+       var named, anonymous bool
+
+       var typ Type
+       var prev syntax.Expr
+       for i, field := range list {
+               ftype := field.Type
+               // type-check type of grouped fields only once
+               if ftype != prev {
+                       prev = ftype
+                       if i == 0 && type0 != nil {
+                               ftype = type0
+                       }
+                       if t, _ := ftype.(*syntax.DotsType); t != nil {
+                               ftype = t.Elem
+                               if variadicOk && i == len(list)-1 {
+                                       variadic = true
+                               } else {
+                                       check.softErrorf(t, "can only use ... with final parameter in list")
+                                       // ignore ... and continue
+                               }
+                       }
+                       typ = check.varType(ftype)
+               }
+               // The parser ensures that f.Tag is nil and we don't
+               // care if a constructed AST contains a non-nil tag.
+               if field.Name != nil {
+                       // named parameter
+                       name := field.Name.Value
+                       if name == "" {
+                               check.invalidASTf(field.Name, "anonymous parameter")
+                               // ok to continue
+                       }
+                       par := NewParam(field.Name.Pos(), check.pkg, name, typ)
+                       check.declare(scope, field.Name, par, scope.pos)
+                       params = append(params, par)
+                       named = true
+               } else {
+                       // anonymous parameter
+                       par := NewParam(ftype.Pos(), check.pkg, "", typ)
+                       check.recordImplicit(field, par)
+                       params = append(params, par)
+                       anonymous = true
+               }
+       }
+
+       if named && anonymous {
+               check.invalidASTf(list[0], "list contains both named and anonymous parameters")
+               // ok to continue
+       }
+
+       // For a variadic function, change the last parameter's type from T to []T.
+       // Since we type-checked T rather than ...T, we also need to retro-actively
+       // record the type for ...T.
+       if variadic {
+               last := params[len(params)-1]
+               last.typ = &Slice{elem: last.typ}
+               check.recordTypeAndValue(list[len(list)-1].Type, typexpr, last.typ, nil)
+       }
+
+       return
+}
+
+func (check *Checker) declareInSet(oset *objset, pos syntax.Pos, obj Object) bool {
+       if alt := oset.insert(obj); alt != nil {
+               check.errorf(pos, "%s redeclared", obj.Name())
+               check.reportAltDecl(alt)
+               return false
+       }
+       return true
+}
+
+func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType, def *Named) {
+       var tname *syntax.Name // most recent "type" name
+       var types []syntax.Expr
+       for _, f := range iface.MethodList {
+               if f.Name != nil {
+                       // We have a method with name f.Name, or a type
+                       // of a type list (f.Name.Value == "type").
+                       name := f.Name.Value
+                       if name == "_" {
+                               if check.conf.CompilerErrorMessages {
+                                       check.errorf(f.Name, "methods must have a unique non-blank name")
+                               } else {
+                                       check.errorf(f.Name, "invalid method name _")
+                               }
+                               continue // ignore
+                       }
+
+                       if name == "type" {
+                               // Always collect all type list entries, even from
+                               // different type lists, under the assumption that
+                               // the author intended to include all types.
+                               types = append(types, f.Type)
+                               if tname != nil && tname != f.Name {
+                                       check.errorf(f.Name, "cannot have multiple type lists in an interface")
+                               }
+                               tname = f.Name
+                               continue
+                       }
+
+                       typ := check.typ(f.Type)
+                       sig, _ := typ.(*Signature)
+                       if sig == nil {
+                               if typ != Typ[Invalid] {
+                                       check.invalidASTf(f.Type, "%s is not a method signature", typ)
+                               }
+                               continue // ignore
+                       }
+
+                       // Always type-check method type parameters but complain if they are not enabled.
+                       // (This extra check is needed here because interface method signatures don't have
+                       // a receiver specification.)
+                       if sig.tparams != nil && !check.conf.AcceptMethodTypeParams {
+                               check.errorf(f.Type, "methods cannot have type parameters")
+                       }
+
+                       // use named receiver type if available (for better error messages)
+                       var recvTyp Type = ityp
+                       if def != nil {
+                               recvTyp = def
+                       }
+                       sig.recv = NewVar(f.Name.Pos(), check.pkg, "", recvTyp)
+
+                       m := NewFunc(f.Name.Pos(), check.pkg, name, sig)
+                       check.recordDef(f.Name, m)
+                       ityp.methods = append(ityp.methods, m)
+               } else {
+                       // We have an embedded type. completeInterface will
+                       // eventually verify that we have an interface.
+                       ityp.embeddeds = append(ityp.embeddeds, check.typ(f.Type))
+                       check.posMap[ityp] = append(check.posMap[ityp], f.Type.Pos())
+               }
+       }
+
+       // type constraints
+       ityp.types = NewSum(check.collectTypeConstraints(iface.Pos(), types))
+
+       if len(ityp.methods) == 0 && ityp.types == nil && len(ityp.embeddeds) == 0 {
+               // empty interface
+               ityp.allMethods = markComplete
+               return
+       }
+
+       // sort for API stability
+       sort.Sort(byUniqueMethodName(ityp.methods))
+       sort.Stable(byUniqueTypeName(ityp.embeddeds))
+
+       check.later(func() { check.completeInterface(iface.Pos(), ityp) })
+}
+
+func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) {
+       if ityp.allMethods != nil {
+               return
+       }
+
+       // completeInterface may be called via the LookupFieldOrMethod,
+       // MissingMethod, Identical, or IdenticalIgnoreTags external API
+       // in which case check will be nil. In this case, type-checking
+       // must be finished and all interfaces should have been completed.
+       if check == nil {
+               panic("internal error: incomplete interface")
+       }
+
+       if check.conf.Trace {
+               // Types don't generally have position information.
+               // If we don't have a valid pos provided, try to use
+               // one close enough.
+               if !pos.IsKnown() && len(ityp.methods) > 0 {
+                       pos = ityp.methods[0].pos
+               }
+
+               check.trace(pos, "complete %s", ityp)
+               check.indent++
+               defer func() {
+                       check.indent--
+                       check.trace(pos, "=> %s (methods = %v, types = %v)", ityp, ityp.allMethods, ityp.allTypes)
+               }()
+       }
+
+       // An infinitely expanding interface (due to a cycle) is detected
+       // elsewhere (Checker.validType), so here we simply assume we only
+       // have valid interfaces. Mark the interface as complete to avoid
+       // infinite recursion if the validType check occurs later for some
+       // reason.
+       ityp.allMethods = markComplete
+
+       // Methods of embedded interfaces are collected unchanged; i.e., the identity
+       // of a method I.m's Func Object of an interface I is the same as that of
+       // the method m in an interface that embeds interface I. On the other hand,
+       // if a method is embedded via multiple overlapping embedded interfaces, we
+       // don't provide a guarantee which "original m" got chosen for the embedding
+       // interface. See also issue #34421.
+       //
+       // If we don't care to provide this identity guarantee anymore, instead of
+       // reusing the original method in embeddings, we can clone the method's Func
+       // Object and give it the position of a corresponding embedded interface. Then
+       // we can get rid of the mpos map below and simply use the cloned method's
+       // position.
+
+       var seen objset
+       var methods []*Func
+       mpos := make(map[*Func]syntax.Pos) // method specification or method embedding position, for good error messages
+       addMethod := func(pos syntax.Pos, m *Func, explicit bool) {
+               switch other := seen.insert(m); {
+               case other == nil:
+                       methods = append(methods, m)
+                       mpos[m] = pos
+               case explicit:
+                       check.errorf(pos, "duplicate method %s", m.name)
+                       check.errorf(mpos[other.(*Func)], "\tother declaration of %s", m.name) // secondary error, \t indented
+               default:
+                       // check method signatures after all types are computed (issue #33656)
+                       check.atEnd(func() {
+                               if !check.identical(m.typ, other.Type()) {
+                                       check.errorf(pos, "duplicate method %s", m.name)
+                                       check.errorf(mpos[other.(*Func)], "\tother declaration of %s", m.name) // secondary error, \t indented
+                               }
+                       })
+               }
+       }
+
+       for _, m := range ityp.methods {
+               addMethod(m.pos, m, true)
+       }
+
+       // collect types
+       allTypes := ityp.types
+
+       posList := check.posMap[ityp]
+       for i, typ := range ityp.embeddeds {
+               pos := posList[i] // embedding position
+               utyp := typ.Under()
+               etyp := utyp.Interface()
+               if etyp == nil {
+                       if utyp != Typ[Invalid] {
+                               var format string
+                               if _, ok := utyp.(*TypeParam); ok {
+                                       format = "%s is a type parameter, not an interface"
+                               } else {
+                                       format = "%s is not an interface"
+                               }
+                               check.errorf(pos, format, typ)
+                       }
+                       continue
+               }
+               check.completeInterface(pos, etyp)
+               for _, m := range etyp.allMethods {
+                       addMethod(pos, m, false) // use embedding position pos rather than m.pos
+               }
+               allTypes = intersect(allTypes, etyp.allTypes)
+       }
+
+       if methods != nil {
+               sort.Sort(byUniqueMethodName(methods))
+               ityp.allMethods = methods
+       }
+       ityp.allTypes = allTypes
+}
+
+// intersect computes the intersection of the types x and y.
+// Note: A incomming nil type stands for the top type. A top
+// type result is returned as nil.
+func intersect(x, y Type) (r Type) {
+       defer func() {
+               if r == theTop {
+                       r = nil
+               }
+       }()
+
+       switch {
+       case x == theBottom || y == theBottom:
+               return theBottom
+       case x == nil || x == theTop:
+               return y
+       case y == nil || x == theTop:
+               return x
+       }
+
+       xtypes := unpack(x)
+       ytypes := unpack(y)
+       // Compute the list rtypes which includes only
+       // types that are in both xtypes and ytypes.
+       // Quadratic algorithm, but good enough for now.
+       // TODO(gri) fix this
+       var rtypes []Type
+       for _, x := range xtypes {
+               if includes(ytypes, x) {
+                       rtypes = append(rtypes, x)
+               }
+       }
+
+       if rtypes == nil {
+               return theBottom
+       }
+       return NewSum(rtypes)
+}
+
+// byUniqueTypeName named type lists can be sorted by their unique type names.
+type byUniqueTypeName []Type
+
+func (a byUniqueTypeName) Len() int           { return len(a) }
+func (a byUniqueTypeName) Less(i, j int) bool { return sortName(a[i]) < sortName(a[j]) }
+func (a byUniqueTypeName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+func sortName(t Type) string {
+       if named := t.Named(); named != nil {
+               return named.obj.Id()
+       }
+       return ""
+}
+
+// byUniqueMethodName method lists can be sorted by their unique method names.
+type byUniqueMethodName []*Func
+
+func (a byUniqueMethodName) Len() int           { return len(a) }
+func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() }
+func (a byUniqueMethodName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+func (check *Checker) tag(t *syntax.BasicLit) string {
+       // If t.Bad, an error was reported during parsing.
+       if t != nil && !t.Bad {
+               if t.Kind == syntax.StringLit {
+                       if val, err := strconv.Unquote(t.Value); err == nil {
+                               return val
+                       }
+               }
+               check.invalidASTf(t, "incorrect tag syntax: %q", t.Value)
+       }
+       return ""
+}
+
+func (check *Checker) structType(styp *Struct, e *syntax.StructType) {
+       if e.FieldList == nil {
+               return
+       }
+
+       // struct fields and tags
+       var fields []*Var
+       var tags []string
+
+       // for double-declaration checks
+       var fset objset
+
+       // current field typ and tag
+       var typ Type
+       var tag string
+       add := func(ident *syntax.Name, embedded bool, pos syntax.Pos) {
+               if tag != "" && tags == nil {
+                       tags = make([]string, len(fields))
+               }
+               if tags != nil {
+                       tags = append(tags, tag)
+               }
+
+               name := ident.Value
+               fld := NewField(pos, check.pkg, name, typ, embedded)
+               // spec: "Within a struct, non-blank field names must be unique."
+               if name == "_" || check.declareInSet(&fset, pos, fld) {
+                       fields = append(fields, fld)
+                       check.recordDef(ident, fld)
+               }
+       }
+
+       // addInvalid adds an embedded field of invalid type to the struct for
+       // fields with errors; this keeps the number of struct fields in sync
+       // with the source as long as the fields are _ or have different names
+       // (issue #25627).
+       addInvalid := func(ident *syntax.Name, pos syntax.Pos) {
+               typ = Typ[Invalid]
+               tag = ""
+               add(ident, true, pos)
+       }
+
+       var prev syntax.Expr
+       for i, f := range e.FieldList {
+               // Fields declared syntactically with the same type (e.g.: a, b, c T)
+               // share the same type expression. Only check type if it's a new type.
+               if i == 0 || f.Type != prev {
+                       typ = check.varType(f.Type)
+                       prev = f.Type
+               }
+               if i < len(e.TagList) {
+                       tag = check.tag(e.TagList[i])
+               }
+               if f.Name != nil {
+                       // named field
+                       add(f.Name, false, f.Name.Pos())
+               } else {
+                       // embedded field
+                       // spec: "An embedded type must be specified as a (possibly parenthesized) type name T or
+                       // as a pointer to a non-interface type name *T, and T itself may not be a pointer type."
+                       pos := startPos(f.Type)
+                       name := embeddedFieldIdent(f.Type)
+                       if name == nil {
+                               check.errorf(pos, "invalid embedded field type %s", f.Type)
+                               name = &syntax.Name{Value: "_"} // TODO(gri) need to set position to pos
+                               addInvalid(name, pos)
+                               continue
+                       }
+                       add(name, true, pos)
+                       // Because we have a name, typ must be of the form T or *T, where T is the name
+                       // of a (named or alias) type, and t (= deref(typ)) must be the type of T.
+                       // We must delay this check to the end because we don't want to instantiate
+                       // (via t.Under()) a possibly incomplete type.
+                       embeddedTyp := typ // for closure below
+                       embeddedPos := pos
+                       check.atEnd(func() {
+                               t, isPtr := deref(embeddedTyp)
+                               switch t := optype(t.Under()).(type) {
+                               case *Basic:
+                                       if t == Typ[Invalid] {
+                                               // error was reported before
+                                               return
+                                       }
+                                       // unsafe.Pointer is treated like a regular pointer
+                                       if t.kind == UnsafePointer {
+                                               check.errorf(embeddedPos, "embedded field type cannot be unsafe.Pointer")
+                                       }
+                               case *Pointer:
+                                       check.errorf(embeddedPos, "embedded field type cannot be a pointer")
+                               case *Interface:
+                                       if isPtr {
+                                               check.errorf(embeddedPos, "embedded field type cannot be a pointer to an interface")
+                                       }
+                               }
+                       })
+               }
+       }
+
+       styp.fields = fields
+       styp.tags = tags
+}
+
+func embeddedFieldIdent(e syntax.Expr) *syntax.Name {
+       switch e := e.(type) {
+       case *syntax.Name:
+               return e
+       case *syntax.Operation:
+               if base := ptrBase(e); base != nil {
+                       // *T is valid, but **T is not
+                       if op, _ := base.(*syntax.Operation); op == nil || ptrBase(op) == nil {
+                               return embeddedFieldIdent(e.X)
+                       }
+               }
+       case *syntax.SelectorExpr:
+               return e.Sel
+       case *syntax.IndexExpr:
+               return embeddedFieldIdent(e.X)
+       case *syntax.ParenExpr:
+               return embeddedFieldIdent(e.X)
+       }
+       return nil // invalid embedded field
+}
+
+func (check *Checker) collectTypeConstraints(pos syntax.Pos, types []syntax.Expr) []Type {
+       list := make([]Type, 0, len(types)) // assume all types are correct
+       for _, texpr := range types {
+               if texpr == nil {
+                       check.invalidASTf(pos, "missing type constraint")
+                       continue
+               }
+               typ := check.varType(texpr)
+               // A type constraint may be a predeclared type or a
+               // composite type composed of only predeclared types.
+               // TODO(gri) If we enable this again it also must run
+               // at the end.
+               const restricted = false
+               var why string
+               if restricted && !check.typeConstraint(typ, &why) {
+                       check.errorf(texpr, "invalid type constraint %s (%s)", typ, why)
+                       continue
+               }
+               list = append(list, typ)
+       }
+
+       // Ensure that each type is only present once in the type list.
+       // Types may be interfaces, which may not be complete yet. It's
+       // ok to do this check at the end because it's not a requirement
+       // for correctness of the code.
+       check.atEnd(func() {
+               uniques := make([]Type, 0, len(list)) // assume all types are unique
+               for i, t := range list {
+                       if t := t.Interface(); t != nil {
+                               check.completeInterface(types[i].Pos(), t)
+                       }
+                       if includes(uniques, t) {
+                               check.softErrorf(types[i], "duplicate type %s in type list", t)
+                       }
+                       uniques = append(uniques, t)
+               }
+       })
+
+       return list
+}
+
+// includes reports whether typ is in list
+func includes(list []Type, typ Type) bool {
+       for _, e := range list {
+               if Identical(typ, e) {
+                       return true
+               }
+       }
+       return false
+}
+
+// typeConstraint checks that typ may be used in a type list.
+// For now this just checks for the absence of defined (*Named) types.
+func (check *Checker) typeConstraint(typ Type, why *string) bool {
+       switch t := typ.(type) {
+       case *Basic:
+               // ok
+       case *Array:
+               return check.typeConstraint(t.elem, why)
+       case *Slice:
+               return check.typeConstraint(t.elem, why)
+       case *Struct:
+               for _, f := range t.fields {
+                       if !check.typeConstraint(f.typ, why) {
+                               return false
+                       }
+               }
+       case *Pointer:
+               return check.typeConstraint(t.base, why)
+       case *Tuple:
+               if t == nil {
+                       return true
+               }
+               for _, v := range t.vars {
+                       if !check.typeConstraint(v.typ, why) {
+                               return false
+                       }
+               }
+       case *Signature:
+               if len(t.tparams) != 0 {
+                       panic("type parameter in function type")
+               }
+               return (t.recv == nil || check.typeConstraint(t.recv.typ, why)) &&
+                       check.typeConstraint(t.params, why) &&
+                       check.typeConstraint(t.results, why)
+       case *Interface:
+               t.assertCompleteness()
+               for _, m := range t.allMethods {
+                       if !check.typeConstraint(m.typ, why) {
+                               return false
+                       }
+               }
+       case *Map:
+               return check.typeConstraint(t.key, why) && check.typeConstraint(t.elem, why)
+       case *Chan:
+               return check.typeConstraint(t.elem, why)
+       case *Named:
+               *why = check.sprintf("contains defined type %s", t)
+               return false
+       case *TypeParam:
+               // ok, e.g.: func f (type T interface { type T }) ()
+       default:
+               unreachable()
+       }
+       return true
+}
+
+func ptrBase(x *syntax.Operation) syntax.Expr {
+       if x.Op == syntax.Mul && x.Y == nil {
+               return x.X
+       }
+       return nil
+}
diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go
new file mode 100644 (file)
index 0000000..60ccf62
--- /dev/null
@@ -0,0 +1,453 @@
+// Copyright 2020 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.
+
+// This file implements type unification.
+
+package types2
+
+import "sort"
+
+// The unifier maintains two separate sets of type parameters x and y
+// which are used to resolve type parameters in the x and y arguments
+// provided to the unify call. For unidirectional unification, only
+// one of these sets (say x) is provided, and then type parameters are
+// only resolved for the x argument passed to unify, not the y argument
+// (even if that also contains possibly the same type parameters). This
+// is crucial to infer the type parameters of self-recursive calls:
+//
+//     func f[P any](a P) { f(a) }
+//
+// For the call f(a) we want to infer that the type argument for P is P.
+// During unification, the parameter type P must be resolved to the type
+// parameter P ("x" side), but the argument type P must be left alone so
+// that unification resolves the type parameter P to P.
+//
+// For bidirection unification, both sets are provided. This enables
+// unification to go from argument to parameter type and vice versa.
+// For constraint type inference, we use bidirectional unification
+// where both the x and y type parameters are identical. This is done
+// by setting up one of them (using init) and then assigning its value
+// to the other.
+
+// A unifier maintains the current type parameters for x and y
+// and the respective types inferred for each type parameter.
+// A unifier is created by calling newUnifier.
+type unifier struct {
+       check *Checker
+       exact bool
+       x, y  tparamsList // x and y must initialized via tparamsList.init
+       types []Type      // inferred types, shared by x and y
+}
+
+// newUnifier returns a new unifier.
+// If exact is set, unification requires unified types to match
+// exactly. If exact is not set, a named type's underlying type
+// is considered if unification would fail otherwise, and the
+// direction of channels is ignored.
+func newUnifier(check *Checker, exact bool) *unifier {
+       u := &unifier{check: check, exact: exact}
+       u.x.unifier = u
+       u.y.unifier = u
+       return u
+}
+
+// unify attempts to unify x and y and reports whether it succeeded.
+func (u *unifier) unify(x, y Type) bool {
+       return u.nify(x, y, nil)
+}
+
+// A tparamsList describes a list of type parameters and the types inferred for them.
+type tparamsList struct {
+       unifier *unifier
+       tparams []*TypeName
+       // For each tparams element, there is a corresponding type slot index in indices.
+       // index  < 0: unifier.types[-index-1] == nil
+       // index == 0: no type slot allocated yet
+       // index  > 0: unifier.types[index-1] == typ
+       // Joined tparams elements share the same type slot and thus have the same index.
+       // By using a negative index for nil types we don't need to check unifier.types
+       // to see if we have a type or not.
+       indices []int // len(d.indices) == len(d.tparams)
+}
+
+// init initializes d with the given type parameters.
+// The type parameters must be in the order in which they appear in their declaration
+// (this ensures that the tparams indices match the respective type parameter index).
+func (d *tparamsList) init(tparams []*TypeName) {
+       if len(tparams) == 0 {
+               return
+       }
+       if debug {
+               for i, tpar := range tparams {
+                       assert(i == tpar.typ.(*TypeParam).index)
+               }
+       }
+       d.tparams = tparams
+       d.indices = make([]int, len(tparams))
+}
+
+// join unifies the i'th type parameter of x with the j'th type parameter of y.
+// If both type parameters already have a type associated with them and they are
+// not joined, join fails and return false.
+func (u *unifier) join(i, j int) bool {
+       ti := u.x.indices[i]
+       tj := u.y.indices[j]
+       switch {
+       case ti == 0 && tj == 0:
+               // Neither type parameter has a type slot associated with them.
+               // Allocate a new joined nil type slot (negative index).
+               u.types = append(u.types, nil)
+               u.x.indices[i] = -len(u.types)
+               u.y.indices[j] = -len(u.types)
+       case ti == 0:
+               // The type parameter for x has no type slot yet. Use slot of y.
+               u.x.indices[i] = tj
+       case tj == 0:
+               // The type parameter for y has no type slot yet. Use slot of x.
+               u.y.indices[j] = ti
+
+       // Both type parameters have a slot: ti != 0 && tj != 0.
+       case ti == tj:
+               // Both type parameters already share the same slot. Nothing to do.
+               break
+       case ti > 0 && tj > 0:
+               // Both type parameters have (possibly different) inferred types. Cannot join.
+               return false
+       case ti > 0:
+               // Only the type parameter for x has an inferred type. Use x slot for y.
+               u.y.setIndex(j, ti)
+       // This case is handled like the default case.
+       // case tj > 0:
+       //      // Only the type parameter for y has an inferred type. Use y slot for x.
+       //      u.x.setIndex(i, tj)
+       default:
+               // Neither type parameter has an inferred type. Use y slot for x
+               // (or x slot for y, it doesn't matter).
+               u.x.setIndex(i, tj)
+       }
+       return true
+}
+
+// If typ is a type parameter of d, index returns the type parameter index.
+// Otherwise, the result is < 0.
+func (d *tparamsList) index(typ Type) int {
+       if t, ok := typ.(*TypeParam); ok {
+               if i := t.index; i < len(d.tparams) && d.tparams[i].typ == t {
+                       return i
+               }
+       }
+       return -1
+}
+
+// setIndex sets the type slot index for the i'th type parameter
+// (and all its joined parameters) to tj. The type parameter
+// must have a (possibly nil) type slot associated with it.
+func (d *tparamsList) setIndex(i, tj int) {
+       ti := d.indices[i]
+       assert(ti != 0 && tj != 0)
+       for k, tk := range d.indices {
+               if tk == ti {
+                       d.indices[k] = tj
+               }
+       }
+}
+
+// at returns the type set for the i'th type parameter; or nil.
+func (d *tparamsList) at(i int) Type {
+       if ti := d.indices[i]; ti > 0 {
+               return d.unifier.types[ti-1]
+       }
+       return nil
+}
+
+// set sets the type typ for the i'th type parameter;
+// typ must not be nil and it must not have been set before.
+func (d *tparamsList) set(i int, typ Type) {
+       assert(typ != nil)
+       u := d.unifier
+       switch ti := d.indices[i]; {
+       case ti < 0:
+               u.types[-ti-1] = typ
+               d.setIndex(i, -ti)
+       case ti == 0:
+               u.types = append(u.types, typ)
+               d.indices[i] = len(u.types)
+       default:
+               panic("type already set")
+       }
+}
+
+// types returns the list of inferred types (via unification) for the type parameters
+// described by d, and an index. If all types were inferred, the returned index is < 0.
+// Otherwise, it is the index of the first type parameter which couldn't be inferred;
+// i.e., for which list[index] is nil.
+func (d *tparamsList) types() (list []Type, index int) {
+       list = make([]Type, len(d.tparams))
+       index = -1
+       for i := range d.tparams {
+               t := d.at(i)
+               list[i] = t
+               if index < 0 && t == nil {
+                       index = i
+               }
+       }
+       return
+}
+
+func (u *unifier) nifyEq(x, y Type, p *ifacePair) bool {
+       return x == y || u.nify(x, y, p)
+}
+
+// nify implements the core unification algorithm which is an
+// adapted version of Checker.identical0. For changes to that
+// code the corresponding changes should be made here.
+// Must not be called directly from outside the unifier.
+func (u *unifier) nify(x, y Type, p *ifacePair) bool {
+       // types must be expanded for comparison
+       x = expand(x)
+       y = expand(y)
+
+       if !u.exact {
+               // If exact unification is known to fail because we attempt to
+               // match a type name against an unnamed type literal, consider
+               // the underlying type of the named type.
+               // (Subtle: We use isNamed to include any type with a name (incl.
+               // basic types and type parameters. We use Named() because we only
+               // want *Named types.)
+               switch {
+               case !isNamed(x) && y != nil && y.Named() != nil:
+                       return u.nify(x, y.Under(), p)
+               case x != nil && x.Named() != nil && !isNamed(y):
+                       return u.nify(x.Under(), y, p)
+               }
+       }
+
+       // Cases where at least one of x or y is a type parameter.
+       switch i, j := u.x.index(x), u.y.index(y); {
+       case i >= 0 && j >= 0:
+               // both x and y are type parameters
+               if u.join(i, j) {
+                       return true
+               }
+               // both x and y have an inferred type - they must match
+               return u.nifyEq(u.x.at(i), u.y.at(j), p)
+
+       case i >= 0:
+               // x is a type parameter, y is not
+               if tx := u.x.at(i); tx != nil {
+                       return u.nifyEq(tx, y, p)
+               }
+               // otherwise, infer type from y
+               u.x.set(i, y)
+               return true
+
+       case j >= 0:
+               // y is a type parameter, x is not
+               if ty := u.y.at(j); ty != nil {
+                       return u.nifyEq(x, ty, p)
+               }
+               // otherwise, infer type from x
+               u.y.set(j, x)
+               return true
+       }
+
+       // For type unification, do not shortcut (x == y) for identical
+       // types. Instead keep comparing them element-wise to unify the
+       // matching (and equal type parameter types). A simple test case
+       // where this matters is: func f[P any](a P) { f(a) } .
+
+       switch x := x.(type) {
+       case *Basic:
+               // Basic types are singletons except for the rune and byte
+               // aliases, thus we cannot solely rely on the x == y check
+               // above. See also comment in TypeName.IsAlias.
+               if y, ok := y.(*Basic); ok {
+                       return x.kind == y.kind
+               }
+
+       case *Array:
+               // Two array types are identical if they have identical element types
+               // and the same array length.
+               if y, ok := y.(*Array); ok {
+                       // If one or both array lengths are unknown (< 0) due to some error,
+                       // assume they are the same to avoid spurious follow-on errors.
+                       return (x.len < 0 || y.len < 0 || x.len == y.len) && u.nify(x.elem, y.elem, p)
+               }
+
+       case *Slice:
+               // Two slice types are identical if they have identical element types.
+               if y, ok := y.(*Slice); ok {
+                       return u.nify(x.elem, y.elem, p)
+               }
+
+       case *Struct:
+               // Two struct types are identical if they have the same sequence of fields,
+               // and if corresponding fields have the same names, and identical types,
+               // and identical tags. Two embedded fields are considered to have the same
+               // name. Lower-case field names from different packages are always different.
+               if y, ok := y.(*Struct); ok {
+                       if x.NumFields() == y.NumFields() {
+                               for i, f := range x.fields {
+                                       g := y.fields[i]
+                                       if f.embedded != g.embedded ||
+                                               x.Tag(i) != y.Tag(i) ||
+                                               !f.sameId(g.pkg, g.name) ||
+                                               !u.nify(f.typ, g.typ, p) {
+                                               return false
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *Pointer:
+               // Two pointer types are identical if they have identical base types.
+               if y, ok := y.(*Pointer); ok {
+                       return u.nify(x.base, y.base, p)
+               }
+
+       case *Tuple:
+               // Two tuples types are identical if they have the same number of elements
+               // and corresponding elements have identical types.
+               if y, ok := y.(*Tuple); ok {
+                       if x.Len() == y.Len() {
+                               if x != nil {
+                                       for i, v := range x.vars {
+                                               w := y.vars[i]
+                                               if !u.nify(v.typ, w.typ, p) {
+                                                       return false
+                                               }
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *Signature:
+               // Two function types are identical if they have the same number of parameters
+               // and result values, corresponding parameter and result types are identical,
+               // and either both functions are variadic or neither is. Parameter and result
+               // names are not required to match.
+               // TODO(gri) handle type parameters or document why we can ignore them.
+               if y, ok := y.(*Signature); ok {
+                       return x.variadic == y.variadic &&
+                               u.nify(x.params, y.params, p) &&
+                               u.nify(x.results, y.results, p)
+               }
+
+       case *Sum:
+               // This should not happen with the current internal use of sum types.
+               panic("type inference across sum types not implemented")
+
+       case *Interface:
+               // Two interface types are identical if they have the same set of methods with
+               // the same names and identical function types. Lower-case method names from
+               // different packages are always different. The order of the methods is irrelevant.
+               if y, ok := y.(*Interface); ok {
+                       // If identical0 is called (indirectly) via an external API entry point
+                       // (such as Identical, IdenticalIgnoreTags, etc.), check is nil. But in
+                       // that case, interfaces are expected to be complete and lazy completion
+                       // here is not needed.
+                       if u.check != nil {
+                               u.check.completeInterface(nopos, x)
+                               u.check.completeInterface(nopos, y)
+                       }
+                       a := x.allMethods
+                       b := y.allMethods
+                       if len(a) == len(b) {
+                               // Interface types are the only types where cycles can occur
+                               // that are not "terminated" via named types; and such cycles
+                               // can only be created via method parameter types that are
+                               // anonymous interfaces (directly or indirectly) embedding
+                               // the current interface. Example:
+                               //
+                               //    type T interface {
+                               //        m() interface{T}
+                               //    }
+                               //
+                               // If two such (differently named) interfaces are compared,
+                               // endless recursion occurs if the cycle is not detected.
+                               //
+                               // If x and y were compared before, they must be equal
+                               // (if they were not, the recursion would have stopped);
+                               // search the ifacePair stack for the same pair.
+                               //
+                               // This is a quadratic algorithm, but in practice these stacks
+                               // are extremely short (bounded by the nesting depth of interface
+                               // type declarations that recur via parameter types, an extremely
+                               // rare occurrence). An alternative implementation might use a
+                               // "visited" map, but that is probably less efficient overall.
+                               q := &ifacePair{x, y, p}
+                               for p != nil {
+                                       if p.identical(q) {
+                                               return true // same pair was compared before
+                                       }
+                                       p = p.prev
+                               }
+                               if debug {
+                                       assert(sort.IsSorted(byUniqueMethodName(a)))
+                                       assert(sort.IsSorted(byUniqueMethodName(b)))
+                               }
+                               for i, f := range a {
+                                       g := b[i]
+                                       if f.Id() != g.Id() || !u.nify(f.typ, g.typ, q) {
+                                               return false
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *Map:
+               // Two map types are identical if they have identical key and value types.
+               if y, ok := y.(*Map); ok {
+                       return u.nify(x.key, y.key, p) && u.nify(x.elem, y.elem, p)
+               }
+
+       case *Chan:
+               // Two channel types are identical if they have identical value types.
+               if y, ok := y.(*Chan); ok {
+                       return (!u.exact || x.dir == y.dir) && u.nify(x.elem, y.elem, p)
+               }
+
+       case *Named:
+               // Two named types are identical if their type names originate
+               // in the same type declaration.
+               // if y, ok := y.(*Named); ok {
+               //      return x.obj == y.obj
+               // }
+               if y, ok := y.(*Named); ok {
+                       // TODO(gri) This is not always correct: two types may have the same names
+                       //           in the same package if one of them is nested in a function.
+                       //           Extremely unlikely but we need an always correct solution.
+                       if x.obj.pkg == y.obj.pkg && x.obj.name == y.obj.name {
+                               assert(len(x.targs) == len(y.targs))
+                               for i, x := range x.targs {
+                                       if !u.nify(x, y.targs[i], p) {
+                                               return false
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *TypeParam:
+               // Two type parameters (which are not part of the type parameters of the
+               // enclosing type as those are handled in the beginning of this function)
+               // are identical if they originate in the same declaration.
+               return x == y
+
+       // case *instance:
+       //      unreachable since types are expanded
+
+       case nil:
+               // avoid a crash in case of nil type
+
+       default:
+               u.check.dump("### u.nify(%s, %s), u.x.tparams = %s", x, y, u.x.tparams)
+               unreachable()
+       }
+
+       return false
+}
diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go
new file mode 100644 (file)
index 0000000..c1961d7
--- /dev/null
@@ -0,0 +1,282 @@
+// UNREVIEWED
+// Copyright 2011 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.
+
+// This file sets up the universe scope and the unsafe package.
+
+package types2
+
+import (
+       "go/constant"
+       "strings"
+)
+
+// The Universe scope contains all predeclared objects of Go.
+// It is the outermost scope of any chain of nested scopes.
+var Universe *Scope
+
+// The Unsafe package is the package returned by an importer
+// for the import path "unsafe".
+var Unsafe *Package
+
+var (
+       universeIota  *Const
+       universeByte  *Basic // uint8 alias, but has name "byte"
+       universeRune  *Basic // int32 alias, but has name "rune"
+       universeAny   *Named
+       universeError *Named
+)
+
+// Typ contains the predeclared *Basic types indexed by their
+// corresponding BasicKind.
+//
+// The *Basic type for Typ[Byte] will have the name "uint8".
+// Use Universe.Lookup("byte").Type() to obtain the specific
+// alias basic type named "byte" (and analogous for "rune").
+var Typ = []*Basic{
+       Invalid: {Invalid, 0, "invalid type", aType{}},
+
+       Bool:          {Bool, IsBoolean, "bool", aType{}},
+       Int:           {Int, IsInteger, "int", aType{}},
+       Int8:          {Int8, IsInteger, "int8", aType{}},
+       Int16:         {Int16, IsInteger, "int16", aType{}},
+       Int32:         {Int32, IsInteger, "int32", aType{}},
+       Int64:         {Int64, IsInteger, "int64", aType{}},
+       Uint:          {Uint, IsInteger | IsUnsigned, "uint", aType{}},
+       Uint8:         {Uint8, IsInteger | IsUnsigned, "uint8", aType{}},
+       Uint16:        {Uint16, IsInteger | IsUnsigned, "uint16", aType{}},
+       Uint32:        {Uint32, IsInteger | IsUnsigned, "uint32", aType{}},
+       Uint64:        {Uint64, IsInteger | IsUnsigned, "uint64", aType{}},
+       Uintptr:       {Uintptr, IsInteger | IsUnsigned, "uintptr", aType{}},
+       Float32:       {Float32, IsFloat, "float32", aType{}},
+       Float64:       {Float64, IsFloat, "float64", aType{}},
+       Complex64:     {Complex64, IsComplex, "complex64", aType{}},
+       Complex128:    {Complex128, IsComplex, "complex128", aType{}},
+       String:        {String, IsString, "string", aType{}},
+       UnsafePointer: {UnsafePointer, 0, "Pointer", aType{}},
+
+       UntypedBool:    {UntypedBool, IsBoolean | IsUntyped, "untyped bool", aType{}},
+       UntypedInt:     {UntypedInt, IsInteger | IsUntyped, "untyped int", aType{}},
+       UntypedRune:    {UntypedRune, IsInteger | IsUntyped, "untyped rune", aType{}},
+       UntypedFloat:   {UntypedFloat, IsFloat | IsUntyped, "untyped float", aType{}},
+       UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, "untyped complex", aType{}},
+       UntypedString:  {UntypedString, IsString | IsUntyped, "untyped string", aType{}},
+       UntypedNil:     {UntypedNil, IsUntyped, "untyped nil", aType{}},
+}
+
+var aliases = [...]*Basic{
+       {Byte, IsInteger | IsUnsigned, "byte", aType{}},
+       {Rune, IsInteger, "rune", aType{}},
+}
+
+func defPredeclaredTypes() {
+       for _, t := range Typ {
+               def(NewTypeName(nopos, nil, t.name, t))
+       }
+       for _, t := range aliases {
+               def(NewTypeName(nopos, nil, t.name, t))
+       }
+
+       // any
+       // (Predeclared and entered into universe scope so we do all the
+       // usual checks; but removed again from scope later since it's
+       // only visible as constraint in a type parameter list.)
+       {
+               typ := &Named{underlying: &emptyInterface}
+               def(NewTypeName(nopos, nil, "any", typ))
+       }
+
+       // Error has a nil package in its qualified name since it is in no package
+       {
+               res := NewVar(nopos, nil, "", Typ[String])
+               sig := &Signature{results: NewTuple(res)}
+               err := NewFunc(nopos, nil, "Error", sig)
+               typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil).Complete()}
+               sig.recv = NewVar(nopos, nil, "", typ)
+               def(NewTypeName(nopos, nil, "error", typ))
+       }
+}
+
+var predeclaredConsts = [...]struct {
+       name string
+       kind BasicKind
+       val  constant.Value
+}{
+       {"true", UntypedBool, constant.MakeBool(true)},
+       {"false", UntypedBool, constant.MakeBool(false)},
+       {"iota", UntypedInt, constant.MakeInt64(0)},
+}
+
+func defPredeclaredConsts() {
+       for _, c := range predeclaredConsts {
+               def(NewConst(nopos, nil, c.name, Typ[c.kind], c.val))
+       }
+}
+
+func defPredeclaredNil() {
+       def(&Nil{object{name: "nil", typ: Typ[UntypedNil], color_: black}})
+}
+
+// A builtinId is the id of a builtin function.
+type builtinId int
+
+const (
+       // universe scope
+       _Append builtinId = iota
+       _Cap
+       _Close
+       _Complex
+       _Copy
+       _Delete
+       _Imag
+       _Len
+       _Make
+       _New
+       _Panic
+       _Print
+       _Println
+       _Real
+       _Recover
+
+       // package unsafe
+       _Alignof
+       _Offsetof
+       _Sizeof
+
+       // testing support
+       _Assert
+       _Trace
+)
+
+var predeclaredFuncs = [...]struct {
+       name     string
+       nargs    int
+       variadic bool
+       kind     exprKind
+}{
+       _Append:  {"append", 1, true, expression},
+       _Cap:     {"cap", 1, false, expression},
+       _Close:   {"close", 1, false, statement},
+       _Complex: {"complex", 2, false, expression},
+       _Copy:    {"copy", 2, false, statement},
+       _Delete:  {"delete", 2, false, statement},
+       _Imag:    {"imag", 1, false, expression},
+       _Len:     {"len", 1, false, expression},
+       _Make:    {"make", 1, true, expression},
+       _New:     {"new", 1, false, expression},
+       _Panic:   {"panic", 1, false, statement},
+       _Print:   {"print", 0, true, statement},
+       _Println: {"println", 0, true, statement},
+       _Real:    {"real", 1, false, expression},
+       _Recover: {"recover", 0, false, statement},
+
+       _Alignof:  {"Alignof", 1, false, expression},
+       _Offsetof: {"Offsetof", 1, false, expression},
+       _Sizeof:   {"Sizeof", 1, false, expression},
+
+       _Assert: {"assert", 1, false, statement},
+       _Trace:  {"trace", 0, true, statement},
+}
+
+func defPredeclaredFuncs() {
+       for i := range predeclaredFuncs {
+               id := builtinId(i)
+               if id == _Assert || id == _Trace {
+                       continue // only define these in testing environment
+               }
+               def(newBuiltin(id))
+       }
+}
+
+// DefPredeclaredTestFuncs defines the assert and trace built-ins.
+// These built-ins are intended for debugging and testing of this
+// package only.
+func DefPredeclaredTestFuncs() {
+       if Universe.Lookup("assert") != nil {
+               return // already defined
+       }
+       def(newBuiltin(_Assert))
+       def(newBuiltin(_Trace))
+}
+
+func defPredeclaredComparable() {
+       // The "comparable" interface can be imagined as defined like
+       //
+       // type comparable interface {
+       //         == () untyped bool
+       //         != () untyped bool
+       // }
+       //
+       // == and != cannot be user-declared but we can declare
+       // a magic method == and check for its presence when needed.
+
+       // Define interface { == () }. We don't care about the signature
+       // for == so leave it empty except for the receiver, which is
+       // set up later to match the usual interface method assumptions.
+       sig := new(Signature)
+       eql := NewFunc(nopos, nil, "==", sig)
+       iface := NewInterfaceType([]*Func{eql}, nil).Complete()
+
+       // set up the defined type for the interface
+       obj := NewTypeName(nopos, nil, "comparable", nil)
+       named := NewNamed(obj, iface, nil)
+       obj.color_ = black
+       sig.recv = NewVar(nopos, nil, "", named) // complete == signature
+
+       def(obj)
+}
+
+func init() {
+       Universe = NewScope(nil, nopos, nopos, "universe")
+       Unsafe = NewPackage("unsafe", "unsafe")
+       Unsafe.complete = true
+
+       defPredeclaredTypes()
+       defPredeclaredConsts()
+       defPredeclaredNil()
+       defPredeclaredFuncs()
+       defPredeclaredComparable()
+
+       universeIota = Universe.Lookup("iota").(*Const)
+       universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic)
+       universeRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic)
+       universeAny = Universe.Lookup("any").(*TypeName).typ.(*Named)
+       universeError = Universe.Lookup("error").(*TypeName).typ.(*Named)
+
+       // "any" is only visible as constraint in a type parameter list
+       delete(Universe.elems, "any")
+}
+
+// Objects with names containing blanks are internal and not entered into
+// a scope. Objects with exported names are inserted in the unsafe package
+// scope; other objects are inserted in the universe scope.
+//
+func def(obj Object) {
+       assert(obj.color() == black)
+       name := obj.Name()
+       if strings.Contains(name, " ") {
+               return // nothing to do
+       }
+       // fix Obj link for named types
+       if typ := obj.Type().Named(); typ != nil {
+               typ.obj = obj.(*TypeName)
+       }
+       // exported identifiers go into package unsafe
+       scope := Universe
+       if obj.Exported() {
+               scope = Unsafe.scope
+               // set Pkg field
+               switch obj := obj.(type) {
+               case *TypeName:
+                       obj.pkg = Unsafe
+               case *Builtin:
+                       obj.pkg = Unsafe
+               default:
+                       unreachable()
+               }
+       }
+       if scope.Insert(obj) != nil {
+               panic("internal error: double declaration")
+       }
+}
diff --git a/src/cmd/compile/internal/types2/walk.go b/src/cmd/compile/internal/types2/walk.go
new file mode 100644 (file)
index 0000000..18cfb28
--- /dev/null
@@ -0,0 +1,322 @@
+// UNREVIEWED
+// Copyright 2012 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.
+
+// This file implements syntax tree walking.
+// TODO(gri) A more general API should probably be in
+//           the syntax package.
+
+package types2
+
+import (
+       "cmd/compile/internal/syntax"
+       "fmt"
+)
+
+// Walk traverses a syntax in pre-order: It starts by calling f(root);
+// root must not be nil. If f returns false (== "continue"), Walk calls
+// f recursively for each of the non-nil children of that node; if f
+// returns true (== "stop"), Walk does not traverse the respective node's
+// children.
+// Some nodes may be shared among multiple parent nodes (e.g., types in
+// field lists such as type T in "a, b, c T"). Such shared nodes are
+// walked multiple times.
+// TODO(gri) Revisit this design. It may make sense to walk those nodes
+//           only once. A place where this matters is TestResolveIdents.
+func Walk(root syntax.Node, f func(syntax.Node) bool) {
+       w := walker{f}
+       w.node(root)
+}
+
+type walker struct {
+       f func(syntax.Node) bool
+}
+
+func (w *walker) node(n syntax.Node) {
+       if n == nil {
+               panic("invalid syntax tree: nil node")
+       }
+
+       if w.f(n) {
+               return
+       }
+
+       switch n := n.(type) {
+       // packages
+       case *syntax.File:
+               w.node(n.PkgName)
+               w.declList(n.DeclList)
+
+       // declarations
+       case *syntax.ImportDecl:
+               if n.LocalPkgName != nil {
+                       w.node(n.LocalPkgName)
+               }
+               w.node(n.Path)
+
+       case *syntax.ConstDecl:
+               w.nameList(n.NameList)
+               if n.Type != nil {
+                       w.node(n.Type)
+               }
+               if n.Values != nil {
+                       w.node(n.Values)
+               }
+
+       case *syntax.TypeDecl:
+               w.node(n.Name)
+               w.fieldList(n.TParamList)
+               w.node(n.Type)
+
+       case *syntax.VarDecl:
+               w.nameList(n.NameList)
+               if n.Type != nil {
+                       w.node(n.Type)
+               }
+               if n.Values != nil {
+                       w.node(n.Values)
+               }
+
+       case *syntax.FuncDecl:
+               if n.Recv != nil {
+                       w.node(n.Recv)
+               }
+               w.node(n.Name)
+               w.fieldList(n.TParamList)
+               w.node(n.Type)
+               if n.Body != nil {
+                       w.node(n.Body)
+               }
+
+       // expressions
+       case *syntax.BadExpr: // nothing to do
+       case *syntax.Name:
+       case *syntax.BasicLit: // nothing to do
+
+       case *syntax.CompositeLit:
+               if n.Type != nil {
+                       w.node(n.Type)
+               }
+               w.exprList(n.ElemList)
+
+       case *syntax.KeyValueExpr:
+               w.node(n.Key)
+               w.node(n.Value)
+
+       case *syntax.FuncLit:
+               w.node(n.Type)
+               w.node(n.Body)
+
+       case *syntax.ParenExpr:
+               w.node(n.X)
+
+       case *syntax.SelectorExpr:
+               w.node(n.X)
+               w.node(n.Sel)
+
+       case *syntax.IndexExpr:
+               w.node(n.X)
+               w.node(n.Index)
+
+       case *syntax.SliceExpr:
+               w.node(n.X)
+               for _, x := range n.Index {
+                       if x != nil {
+                               w.node(x)
+                       }
+               }
+
+       case *syntax.AssertExpr:
+               w.node(n.X)
+               w.node(n.Type)
+
+       case *syntax.TypeSwitchGuard:
+               if n.Lhs != nil {
+                       w.node(n.Lhs)
+               }
+               w.node(n.X)
+
+       case *syntax.Operation:
+               w.node(n.X)
+               if n.Y != nil {
+                       w.node(n.Y)
+               }
+
+       case *syntax.CallExpr:
+               w.node(n.Fun)
+               w.exprList(n.ArgList)
+
+       case *syntax.ListExpr:
+               w.exprList(n.ElemList)
+
+       // types
+       case *syntax.ArrayType:
+               if n.Len != nil {
+                       w.node(n.Len)
+               }
+               w.node(n.Elem)
+
+       case *syntax.SliceType:
+               w.node(n.Elem)
+
+       case *syntax.DotsType:
+               w.node(n.Elem)
+
+       case *syntax.StructType:
+               w.fieldList(n.FieldList)
+               for _, t := range n.TagList {
+                       if t != nil {
+                               w.node(t)
+                       }
+               }
+
+       case *syntax.Field:
+               if n.Name != nil {
+                       w.node(n.Name)
+               }
+               w.node(n.Type)
+
+       case *syntax.InterfaceType:
+               w.fieldList(n.MethodList)
+
+       case *syntax.FuncType:
+               w.fieldList(n.ParamList)
+               w.fieldList(n.ResultList)
+
+       case *syntax.MapType:
+               w.node(n.Key)
+               w.node(n.Value)
+
+       case *syntax.ChanType:
+               w.node(n.Elem)
+
+       // statements
+       case *syntax.EmptyStmt: // nothing to do
+
+       case *syntax.LabeledStmt:
+               w.node(n.Label)
+               w.node(n.Stmt)
+
+       case *syntax.BlockStmt:
+               w.stmtList(n.List)
+
+       case *syntax.ExprStmt:
+               w.node(n.X)
+
+       case *syntax.SendStmt:
+               w.node(n.Chan)
+               w.node(n.Value)
+
+       case *syntax.DeclStmt:
+               w.declList(n.DeclList)
+
+       case *syntax.AssignStmt:
+               w.node(n.Lhs)
+               w.node(n.Rhs)
+
+       case *syntax.BranchStmt:
+               if n.Label != nil {
+                       w.node(n.Label)
+               }
+               // Target points to nodes elsewhere in the syntax tree
+
+       case *syntax.CallStmt:
+               w.node(n.Call)
+
+       case *syntax.ReturnStmt:
+               if n.Results != nil {
+                       w.node(n.Results)
+               }
+
+       case *syntax.IfStmt:
+               if n.Init != nil {
+                       w.node(n.Init)
+               }
+               w.node(n.Cond)
+               w.node(n.Then)
+               if n.Else != nil {
+                       w.node(n.Else)
+               }
+
+       case *syntax.ForStmt:
+               if n.Init != nil {
+                       w.node(n.Init)
+               }
+               if n.Cond != nil {
+                       w.node(n.Cond)
+               }
+               if n.Post != nil {
+                       w.node(n.Post)
+               }
+               w.node(n.Body)
+
+       case *syntax.SwitchStmt:
+               if n.Init != nil {
+                       w.node(n.Init)
+               }
+               if n.Tag != nil {
+                       w.node(n.Tag)
+               }
+               for _, s := range n.Body {
+                       w.node(s)
+               }
+
+       case *syntax.SelectStmt:
+               for _, s := range n.Body {
+                       w.node(s)
+               }
+
+       // helper nodes
+       case *syntax.RangeClause:
+               if n.Lhs != nil {
+                       w.node(n.Lhs)
+               }
+               w.node(n.X)
+
+       case *syntax.CaseClause:
+               if n.Cases != nil {
+                       w.node(n.Cases)
+               }
+               w.stmtList(n.Body)
+
+       case *syntax.CommClause:
+               if n.Comm != nil {
+                       w.node(n.Comm)
+               }
+               w.stmtList(n.Body)
+
+       default:
+               panic(fmt.Sprintf("internal error: unknown node type %T", n))
+       }
+}
+
+func (w *walker) declList(list []syntax.Decl) {
+       for _, n := range list {
+               w.node(n)
+       }
+}
+
+func (w *walker) exprList(list []syntax.Expr) {
+       for _, n := range list {
+               w.node(n)
+       }
+}
+
+func (w *walker) stmtList(list []syntax.Stmt) {
+       for _, n := range list {
+               w.node(n)
+       }
+}
+
+func (w *walker) nameList(list []*syntax.Name) {
+       for _, n := range list {
+               w.node(n)
+       }
+}
+
+func (w *walker) fieldList(list []*syntax.Field) {
+       for _, n := range list {
+               w.node(n)
+       }
+}
index 5e1647cbf063c1853ffe158f96f0a5877ef0de28..4dda70d124ad06b72d04b5a306c5ef9d104cbd9a 100644 (file)
@@ -42,6 +42,7 @@ var bootstrapDirs = []string{
        "cmd/compile/internal/arm",
        "cmd/compile/internal/arm64",
        "cmd/compile/internal/gc",
+       "cmd/compile/internal/importer",
        "cmd/compile/internal/ir",
        "cmd/compile/internal/logopt",
        "cmd/compile/internal/mips",
@@ -52,6 +53,7 @@ var bootstrapDirs = []string{
        "cmd/compile/internal/ssa",
        "cmd/compile/internal/syntax",
        "cmd/compile/internal/types",
+       "cmd/compile/internal/types2",
        "cmd/compile/internal/x86",
        "cmd/compile/internal/wasm",
        "cmd/internal/bio",
index 300966a32638009c3b8d44f84e297d116c6e37e5..2456020c5ef336681a01317b5dbe02660b2240cf 100644 (file)
@@ -193,11 +193,14 @@ func isDirective(c string) bool {
 // in a signature.
 // Field.Names is nil for unnamed parameters (parameter lists which only contain types)
 // and embedded struct fields. In the latter case, the field name is the type name.
+// Field.Names contains a single name "type" for elements of interface type lists.
+// Types belonging to the same type list share the same "type" identifier which also
+// records the position of that keyword.
 //
 type Field struct {
        Doc     *CommentGroup // associated documentation; or nil
-       Names   []*Ident      // field/method/parameter names; or nil
-       Type    Expr          // field/method/parameter type
+       Names   []*Ident      // field/method/(type) parameter names, or type "type"; or nil
+       Type    Expr          // field/method/parameter type, type list type; or nil
        Tag     *BasicLit     // field tag; or nil
        Comment *CommentGroup // line comments; or nil
 }
@@ -206,14 +209,23 @@ func (f *Field) Pos() token.Pos {
        if len(f.Names) > 0 {
                return f.Names[0].Pos()
        }
-       return f.Type.Pos()
+       if f.Type != nil {
+               return f.Type.Pos()
+       }
+       return token.NoPos
 }
 
 func (f *Field) End() token.Pos {
        if f.Tag != nil {
                return f.Tag.End()
        }
-       return f.Type.End()
+       if f.Type != nil {
+               return f.Type.End()
+       }
+       if len(f.Names) > 0 {
+               return f.Names[len(f.Names)-1].End()
+       }
+       return token.NoPos
 }
 
 // A FieldList represents a list of Fields, enclosed by parentheses or braces.
@@ -247,7 +259,7 @@ func (f *FieldList) End() token.Pos {
        return token.NoPos
 }
 
-// NumFields returns the number of parameters or struct fields represented by a FieldList.
+// NumFields returns the number of (type) parameters or struct fields represented by a FieldList.
 func (f *FieldList) NumFields() int {
        n := 0
        if f != nil {
@@ -290,12 +302,6 @@ type (
        }
 
        // A BasicLit node represents a literal of basic type.
-       //
-       // Note that for the CHAR and STRING kinds, the literal is stored
-       // with its quotes. For example, for a double-quoted STRING, the
-       // first and the last rune in the Value field will be ". The
-       // Unquote and UnquoteChar functions in the strconv package can be
-       // used to unquote STRING and CHAR values, respectively.
        BasicLit struct {
                ValuePos token.Pos   // literal position
                Kind     token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING
@@ -366,6 +372,9 @@ type (
                Args     []Expr    // function arguments; or nil
                Ellipsis token.Pos // position of "..." (token.NoPos if there is no "...")
                Rparen   token.Pos // position of ")"
+               // TODO(rFindley) use a new ListExpr type rather than overloading CallExpr
+               //                via Brackets, as is done in the syntax package
+               Brackets bool // if set, "[" and "]" are used instead of "(" and ")"
        }
 
        // A StarExpr node represents an expression of the form "*" Expression.
@@ -437,6 +446,7 @@ type (
        // A FuncType node represents a function type.
        FuncType struct {
                Func    token.Pos  // position of "func" keyword (token.NoPos if there is no "func")
+               TParams *FieldList // type parameters; or nil
                Params  *FieldList // (incoming) parameters; non-nil
                Results *FieldList // (outgoing) results; or nil
        }
@@ -444,8 +454,8 @@ type (
        // An InterfaceType node represents an interface type.
        InterfaceType struct {
                Interface  token.Pos  // position of "interface" keyword
-               Methods    *FieldList // list of methods
-               Incomplete bool       // true if (source) methods are missing in the Methods list
+               Methods    *FieldList // list of embedded interfaces, methods, or types
+               Incomplete bool       // true if (source) methods or types are missing in the Methods list
        }
 
        // A MapType node represents a map type.
@@ -898,6 +908,7 @@ type (
        TypeSpec struct {
                Doc     *CommentGroup // associated documentation; or nil
                Name    *Ident        // type name
+               TParams *FieldList    // type parameters; or nil
                Assign  token.Pos     // position of '=', if any
                Type    Expr          // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
                Comment *CommentGroup // line comments; or nil
@@ -965,7 +976,7 @@ type (
        GenDecl struct {
                Doc    *CommentGroup // associated documentation; or nil
                TokPos token.Pos     // position of Tok
-               Tok    token.Token   // IMPORT, CONST, TYPE, VAR
+               Tok    token.Token   // IMPORT, CONST, TYPE, or VAR
                Lparen token.Pos     // position of '(', if any
                Specs  []Spec
                Rparen token.Pos // position of ')', if any
@@ -976,11 +987,17 @@ type (
                Doc  *CommentGroup // associated documentation; or nil
                Recv *FieldList    // receiver (methods); or nil (functions)
                Name *Ident        // function/method name
-               Type *FuncType     // function signature: parameters, results, and position of "func" keyword
+               Type *FuncType     // function signature: type and value parameters, results, and position of "func" keyword
                Body *BlockStmt    // function body; or nil for external (non-Go) function
+               // TODO(rFindley) consider storing TParams here, rather than FuncType, as
+               //                they are only valid for declared functions
        }
 )
 
+func (f *FuncDecl) IsMethod() bool {
+       return f.Recv.NumFields() != 0
+}
+
 // Pos and End implementations for declaration nodes.
 
 func (d *BadDecl) Pos() token.Pos  { return d.From }
index e3013f64bed87e3e8ff2e41311688346b5cea41f..c2b35205bbc8c8d1510b0d94490b50b76b28ad95 100644 (file)
@@ -119,22 +119,23 @@ func main() {
        //     40  .  .  .  .  .  .  .  }
        //     41  .  .  .  .  .  .  .  Ellipsis: -
        //     42  .  .  .  .  .  .  .  Rparen: 4:25
-       //     43  .  .  .  .  .  .  }
-       //     44  .  .  .  .  .  }
-       //     45  .  .  .  .  }
-       //     46  .  .  .  .  Rbrace: 5:1
-       //     47  .  .  .  }
-       //     48  .  .  }
-       //     49  .  }
-       //     50  .  Scope: *ast.Scope {
-       //     51  .  .  Objects: map[string]*ast.Object (len = 1) {
-       //     52  .  .  .  "main": *(obj @ 11)
-       //     53  .  .  }
-       //     54  .  }
-       //     55  .  Unresolved: []*ast.Ident (len = 1) {
-       //     56  .  .  0: *(obj @ 29)
-       //     57  .  }
-       //     58  }
+       //     43  .  .  .  .  .  .  .  Brackets: false
+       //     44  .  .  .  .  .  .  }
+       //     45  .  .  .  .  .  }
+       //     46  .  .  .  .  }
+       //     47  .  .  .  .  Rbrace: 5:1
+       //     48  .  .  .  }
+       //     49  .  .  }
+       //     50  .  }
+       //     51  .  Scope: *ast.Scope {
+       //     52  .  .  Objects: map[string]*ast.Object (len = 1) {
+       //     53  .  .  .  "main": *(obj @ 11)
+       //     54  .  .  }
+       //     55  .  }
+       //     56  .  Unresolved: []*ast.Ident (len = 1) {
+       //     57  .  .  0: *(obj @ 29)
+       //     58  .  }
+       //     59  }
 }
 
 // This example illustrates how to remove a variable declaration
index 8ca21959b11a012cae79c9f018100cb3bf1fe7fc..f909c00b4bdc236f16907d7abfdb7a06ca02a189 100644 (file)
@@ -71,7 +71,9 @@ func Walk(v Visitor, node Node) {
                        Walk(v, n.Doc)
                }
                walkIdentList(v, n.Names)
-               Walk(v, n.Type)
+               if n.Type != nil {
+                       Walk(v, n.Type)
+               }
                if n.Tag != nil {
                        Walk(v, n.Tag)
                }
@@ -161,6 +163,9 @@ func Walk(v Visitor, node Node) {
                Walk(v, n.Fields)
 
        case *FuncType:
+               if n.TParams != nil {
+                       Walk(v, n.TParams)
+               }
                if n.Params != nil {
                        Walk(v, n.Params)
                }
@@ -315,6 +320,9 @@ func Walk(v Visitor, node Node) {
                        Walk(v, n.Doc)
                }
                Walk(v, n.Name)
+               if n.TParams != nil {
+                       Walk(v, n.TParams)
+               }
                Walk(v, n.Type)
                if n.Comment != nil {
                        Walk(v, n.Comment)
index 35240c8fe68745f1df00117e34471d5d11843adc..c5b520feb4c11a937597ac4e1e53180e05290d30 100644 (file)
@@ -94,7 +94,7 @@ var importerTests = [...]importerTest{
        {pkgpath: "nointerface", name: "I", want: "type I int"},
        {pkgpath: "issue29198", name: "FooServer", gccgoVersion: 7, want: "type FooServer struct{FooServer *FooServer; user string; ctx context.Context}"},
        {pkgpath: "issue30628", name: "Apple", want: "type Apple struct{hey sync.RWMutex; x int; RQ [517]struct{Count uintptr; NumBytes uintptr; Last uintptr}}"},
-       {pkgpath: "issue31540", name: "S", gccgoVersion: 7, want: "type S struct{b int; map[Y]Z}"},
+       {pkgpath: "issue31540", name: "S", gccgoVersion: 7, want: "type S struct{b int; A2 /* = map[Y]Z */}"},
        {pkgpath: "issue34182", name: "T1", want: "type T1 struct{f *T2}"},
        {pkgpath: "notinheap", name: "S", want: "type S struct{}"},
 }
index 358a844f65a6657107ebb6d2d49a8afa202a80b7..8e20b7b468c96d0a920d37a3732e677c3a4e7cc2 100644 (file)
@@ -114,6 +114,7 @@ func expectedErrors(fset *token.FileSet, filename string, src []byte) map[token.
 // of found errors and reports discrepancies.
 //
 func compareErrors(t *testing.T, fset *token.FileSet, expected map[token.Pos]string, found scanner.ErrorList) {
+       t.Helper()
        for _, error := range found {
                // error.Pos is a token.Position, but we want
                // a token.Pos so we can do a map lookup
@@ -149,7 +150,8 @@ func compareErrors(t *testing.T, fset *token.FileSet, expected map[token.Pos]str
        }
 }
 
-func checkErrors(t *testing.T, filename string, input interface{}) {
+func checkErrors(t *testing.T, filename string, input interface{}, mode Mode, expectErrors bool) {
+       t.Helper()
        src, err := readSource(filename, input)
        if err != nil {
                t.Error(err)
@@ -157,7 +159,7 @@ func checkErrors(t *testing.T, filename string, input interface{}) {
        }
 
        fset := token.NewFileSet()
-       _, err = ParseFile(fset, filename, src, DeclarationErrors|AllErrors)
+       _, err = ParseFile(fset, filename, src, mode)
        found, ok := err.(scanner.ErrorList)
        if err != nil && !ok {
                t.Error(err)
@@ -165,9 +167,12 @@ func checkErrors(t *testing.T, filename string, input interface{}) {
        }
        found.RemoveMultiples()
 
-       // we are expecting the following errors
-       // (collect these after parsing a file so that it is found in the file set)
-       expected := expectedErrors(fset, filename, src)
+       expected := map[token.Pos]string{}
+       if expectErrors {
+               // we are expecting the following errors
+               // (collect these after parsing a file so that it is found in the file set)
+               expected = expectedErrors(fset, filename, src)
+       }
 
        // verify errors returned by the parser
        compareErrors(t, fset, expected, found)
@@ -180,8 +185,12 @@ func TestErrors(t *testing.T) {
        }
        for _, d := range list {
                name := d.Name()
-               if !d.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".src") {
-                       checkErrors(t, filepath.Join(testdata, name), nil)
+               if !d.IsDir() && !strings.HasPrefix(name, ".") && (strings.HasSuffix(name, ".src") || strings.HasSuffix(name, ".go2")) {
+                       mode := DeclarationErrors | AllErrors
+                       if strings.HasSuffix(name, ".go2") {
+                               mode |= ParseTypeParams
+                       }
+                       checkErrors(t, filepath.Join(testdata, name), nil, mode, true)
                }
        }
 }
index 56ff5fefb4f095408d2ba01dde0d33ea6a5d190d..b8b312463ff93f5225f980c65fd19e541df4a29b 100644 (file)
@@ -55,6 +55,7 @@ const (
        Trace                                          // print a trace of parsed productions
        DeclarationErrors                              // report declaration errors
        SpuriousErrors                                 // same as AllErrors, for backward-compatibility
+       ParseTypeParams                                // Placeholder. Will control the parsing of type parameters.
        AllErrors         = SpuriousErrors             // report all errors (not just the first 10 on different lines)
 )
 
index 31a73985bf3b567381114da88162ef9ce7b50920..24e84d5103a7aea8cc141a1206aefcb63832993d 100644 (file)
@@ -34,7 +34,7 @@ type parser struct {
 
        // Tracing/debugging
        mode   Mode // parsing mode
-       trace  bool // == (mode & Trace != 0)
+       trace  bool // == (mode&Trace != 0)
        indent int  // indentation used for tracing output
 
        // Comments
@@ -181,7 +181,7 @@ func (p *parser) tryResolve(x ast.Expr, collectUnresolved bool) {
        if ident == nil {
                return
        }
-       assert(ident.Obj == nil, "identifier already declared or resolved")
+       assert(ident.Obj == nil, fmt.Sprintf("identifier %s already declared or resolved", ident.Name))
        if ident.Name == "_" {
                return
        }
@@ -352,6 +352,10 @@ func (p *parser) next() {
 type bailout struct{}
 
 func (p *parser) error(pos token.Pos, msg string) {
+       if p.trace {
+               defer un(trace(p, "error: "+msg))
+       }
+
        epos := p.file.Position(pos)
 
        // If AllErrors is not set, discard errors reported on the same line
@@ -594,9 +598,7 @@ func (p *parser) parseLhsList() []ast.Expr {
        switch p.tok {
        case token.DEFINE:
                // lhs of a short variable declaration
-               // but doesn't enter scope until later:
-               // caller must call p.shortVarDecl(p.makeIdentList(list))
-               // at appropriate time.
+               // but doesn't enter scope until later.
        case token.COLON:
                // lhs of a label declaration or a communication clause of a select
                // statement (parseLhsList is not called when parsing the case clause
@@ -643,14 +645,29 @@ func (p *parser) parseType() ast.Expr {
        return typ
 }
 
+func (p *parser) parseQualifiedIdent(ident *ast.Ident) ast.Expr {
+       if p.trace {
+               defer un(trace(p, "QualifiedIdent"))
+       }
+
+       typ := p.parseTypeName(ident)
+       if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 {
+               typ = p.parseTypeInstance(typ)
+       }
+
+       return typ
+}
+
 // If the result is an identifier, it is not resolved.
-func (p *parser) parseTypeName() ast.Expr {
+func (p *parser) parseTypeName(ident *ast.Ident) ast.Expr {
        if p.trace {
                defer un(trace(p, "TypeName"))
        }
 
-       ident := p.parseIdent()
-       // don't resolve ident yet - it may be a parameter or field name
+       if ident == nil {
+               ident = p.parseIdent()
+               // don't resolve ident yet - it may be a parameter or field name
+       }
 
        if p.tok == token.PERIOD {
                // ident is a package name
@@ -663,12 +680,11 @@ func (p *parser) parseTypeName() ast.Expr {
        return ident
 }
 
-func (p *parser) parseArrayType() ast.Expr {
+func (p *parser) parseArrayLen() ast.Expr {
        if p.trace {
-               defer un(trace(p, "ArrayType"))
+               defer un(trace(p, "ArrayLen"))
        }
 
-       lbrack := p.expect(token.LBRACK)
        p.exprLev++
        var len ast.Expr
        // always permit ellipsis for more fault-tolerant parsing
@@ -679,26 +695,66 @@ func (p *parser) parseArrayType() ast.Expr {
                len = p.parseRhs()
        }
        p.exprLev--
-       p.expect(token.RBRACK)
-       elt := p.parseType()
 
-       return &ast.ArrayType{Lbrack: lbrack, Len: len, Elt: elt}
+       return len
 }
 
-func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
-       idents := make([]*ast.Ident, len(list))
-       for i, x := range list {
-               ident, isIdent := x.(*ast.Ident)
-               if !isIdent {
-                       if _, isBad := x.(*ast.BadExpr); !isBad {
-                               // only report error if it's a new one
-                               p.errorExpected(x.Pos(), "identifier")
+func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Expr) {
+       if p.trace {
+               defer un(trace(p, "ArrayFieldOrTypeInstance"))
+       }
+
+       // TODO(gri) Should we allow a trailing comma in a type argument
+       //           list such as T[P,]? (We do in parseTypeInstance).
+       lbrack := p.expect(token.LBRACK)
+       var args []ast.Expr
+       var firstComma token.Pos
+       // TODO(rfindley): consider changing parseRhsOrType so that this function variable
+       // is not needed.
+       argparser := p.parseRhsOrType
+       if p.mode&ParseTypeParams == 0 {
+               argparser = p.parseRhs
+       }
+       if p.tok != token.RBRACK {
+               p.exprLev++
+               args = append(args, argparser())
+               for p.tok == token.COMMA {
+                       if !firstComma.IsValid() {
+                               firstComma = p.pos
                        }
-                       ident = &ast.Ident{NamePos: x.Pos(), Name: "_"}
+                       p.next()
+                       args = append(args, argparser())
+               }
+               p.exprLev--
+       }
+       rbrack := p.expect(token.RBRACK)
+
+       if len(args) == 0 {
+               // x []E
+               elt := p.parseType()
+               return x, &ast.ArrayType{Lbrack: lbrack, Elt: elt}
+       }
+
+       // x [P]E or x[P]
+       if len(args) == 1 {
+               elt := p.tryType()
+               if elt != nil {
+                       // x [P]E
+                       return x, &ast.ArrayType{Lbrack: lbrack, Len: args[0], Elt: elt}
+               }
+               if p.mode&ParseTypeParams == 0 {
+                       p.error(rbrack, "missing element type in array type expression")
+                       return nil, &ast.BadExpr{From: args[0].Pos(), To: args[0].End()}
                }
-               idents[i] = ident
        }
-       return idents
+
+       if p.mode&ParseTypeParams == 0 {
+               p.error(firstComma, "expected ']', found ','")
+               return x, &ast.BadExpr{From: args[0].Pos(), To: args[len(args)-1].End()}
+       }
+
+       // x[P], x[P1, P2], ...
+       return nil, &ast.CallExpr{Fun: x, Lparen: lbrack, Args: args, Rparen: rbrack, Brackets: true}
 }
 
 func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
@@ -708,37 +764,44 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
 
        doc := p.leadComment
 
-       // 1st FieldDecl
-       // A type name used as an anonymous field looks like a field identifier.
-       var list []ast.Expr
-       for {
-               list = append(list, p.parseVarType(false))
-               if p.tok != token.COMMA {
-                       break
+       var names []*ast.Ident
+       var typ ast.Expr
+       if p.tok == token.IDENT {
+               name := p.parseIdent()
+               if p.tok == token.PERIOD || p.tok == token.STRING || p.tok == token.SEMICOLON || p.tok == token.RBRACE {
+                       // embedded type
+                       typ = name
+                       if p.tok == token.PERIOD {
+                               typ = p.parseQualifiedIdent(name)
+                       } else {
+                               p.resolve(typ)
+                       }
+               } else {
+                       // name1, name2, ... T
+                       names = []*ast.Ident{name}
+                       for p.tok == token.COMMA {
+                               p.next()
+                               names = append(names, p.parseIdent())
+                       }
+                       // Careful dance: We don't know if we have an embedded instantiated
+                       // type T[P1, P2, ...] or a field T of array type []E or [P]E.
+                       if len(names) == 1 && p.tok == token.LBRACK {
+                               name, typ = p.parseArrayFieldOrTypeInstance(name)
+                               if name == nil {
+                                       names = nil
+                               }
+                       } else {
+                               // T P
+                               typ = p.parseType()
+                       }
                }
-               p.next()
-       }
-
-       typ := p.tryVarType(false)
-
-       // analyze case
-       var idents []*ast.Ident
-       if typ != nil {
-               // IdentifierList Type
-               idents = p.makeIdentList(list)
        } else {
-               // ["*"] TypeName (AnonymousField)
-               typ = list[0] // we always have at least one element
-               if n := len(list); n > 1 {
-                       p.errorExpected(p.pos, "type")
-                       typ = &ast.BadExpr{From: p.pos, To: p.pos}
-               } else if !isTypeName(deref(typ)) {
-                       p.errorExpected(typ.Pos(), "anonymous field")
-                       typ = &ast.BadExpr{From: typ.Pos(), To: p.safePos(typ.End())}
-               }
+               // embedded, possibly generic type
+               // (using the enclosing parentheses to distinguish it from a named field declaration)
+               // TODO(rFindley) confirm that this doesn't allow parenthesized embedded type
+               typ = p.parseType()
        }
 
-       // Tag
        var tag *ast.BasicLit
        if p.tok == token.STRING {
                tag = &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
@@ -747,10 +810,8 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
 
        p.expectSemi() // call before accessing p.linecomment
 
-       field := &ast.Field{Doc: doc, Names: idents, Type: typ, Tag: tag, Comment: p.lineComment}
-       p.declare(field, nil, scope, ast.Var, idents...)
-       p.resolve(typ)
-
+       field := &ast.Field{Doc: doc, Names: names, Type: typ, Tag: tag, Comment: p.lineComment}
+       p.declare(field, nil, scope, ast.Var, names...)
        return field
 }
 
@@ -792,107 +853,223 @@ func (p *parser) parsePointerType() *ast.StarExpr {
        return &ast.StarExpr{Star: star, X: base}
 }
 
-// If the result is an identifier, it is not resolved.
-func (p *parser) tryVarType(isParam bool) ast.Expr {
-       if isParam && p.tok == token.ELLIPSIS {
-               pos := p.pos
-               p.next()
-               typ := p.tryIdentOrType() // don't use parseType so we can provide better error message
-               if typ != nil {
-                       p.resolve(typ)
-               } else {
-                       p.error(pos, "'...' parameter is missing type")
-                       typ = &ast.BadExpr{From: pos, To: p.pos}
-               }
-               return &ast.Ellipsis{Ellipsis: pos, Elt: typ}
+func (p *parser) parseDotsType() *ast.Ellipsis {
+       if p.trace {
+               defer un(trace(p, "DotsType"))
        }
-       return p.tryIdentOrType()
+
+       pos := p.expect(token.ELLIPSIS)
+       elt := p.parseType()
+
+       return &ast.Ellipsis{Ellipsis: pos, Elt: elt}
 }
 
-// If the result is an identifier, it is not resolved.
-func (p *parser) parseVarType(isParam bool) ast.Expr {
-       typ := p.tryVarType(isParam)
-       if typ == nil {
-               pos := p.pos
-               p.errorExpected(pos, "type")
-               p.next() // make progress
-               typ = &ast.BadExpr{From: pos, To: p.pos}
+type field struct {
+       name *ast.Ident
+       typ  ast.Expr
+}
+
+func (p *parser) parseParamDecl(name *ast.Ident) (f field) {
+       // TODO(rFindley) compare with parser.paramDeclOrNil in the syntax package
+       if p.trace {
+               defer un(trace(p, "ParamDeclOrNil"))
        }
-       return typ
+
+       ptok := p.tok
+       if name != nil {
+               p.tok = token.IDENT // force token.IDENT case in switch below
+       }
+
+       switch p.tok {
+       case token.IDENT:
+               if name != nil {
+                       f.name = name
+                       p.tok = ptok
+               } else {
+                       f.name = p.parseIdent()
+               }
+               switch p.tok {
+               case token.IDENT, token.MUL, token.ARROW, token.FUNC, token.CHAN, token.MAP, token.STRUCT, token.INTERFACE, token.LPAREN:
+                       // name type
+                       f.typ = p.parseType()
+
+               case token.LBRACK:
+                       // name[type1, type2, ...] or name []type or name [len]type
+                       f.name, f.typ = p.parseArrayFieldOrTypeInstance(f.name)
+
+               case token.ELLIPSIS:
+                       // name ...type
+                       f.typ = p.parseDotsType()
+
+               case token.PERIOD:
+                       // qualified.typename
+                       f.typ = p.parseQualifiedIdent(f.name)
+                       f.name = nil
+               }
+
+       case token.MUL, token.ARROW, token.FUNC, token.LBRACK, token.CHAN, token.MAP, token.STRUCT, token.INTERFACE, token.LPAREN:
+               // type
+               f.typ = p.parseType()
+
+       case token.ELLIPSIS:
+               // ...type
+               // (always accepted)
+               f.typ = p.parseDotsType()
+
+       default:
+               p.errorExpected(p.pos, ")")
+               p.advance(exprEnd)
+       }
+
+       return
 }
 
-func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
+func (p *parser) parseParameterList(scope *ast.Scope, name0 *ast.Ident, closing token.Token, parseParamDecl func(*ast.Ident) field, tparams bool) (params []*ast.Field) {
        if p.trace {
                defer un(trace(p, "ParameterList"))
        }
 
-       // 1st ParameterDecl
-       // A list of identifiers looks like a list of type names.
-       var list []ast.Expr
-       for {
-               list = append(list, p.parseVarType(ellipsisOk))
-               if p.tok != token.COMMA {
-                       break
+       pos := p.pos
+       if name0 != nil {
+               pos = name0.Pos()
+       }
+
+       var list []field
+       var named int // number of parameters that have an explicit name and type
+
+       for name0 != nil || p.tok != closing && p.tok != token.EOF {
+               par := parseParamDecl(name0)
+               name0 = nil // 1st name was consumed if present
+               if par.name != nil || par.typ != nil {
+                       list = append(list, par)
+                       if par.name != nil && par.typ != nil {
+                               named++
+                       }
                }
-               p.next()
-               if p.tok == token.RPAREN {
+               if !p.atComma("parameter list", closing) {
                        break
                }
+               p.next()
        }
 
-       // analyze case
-       if typ := p.tryVarType(ellipsisOk); typ != nil {
-               // IdentifierList Type
-               idents := p.makeIdentList(list)
-               field := &ast.Field{Names: idents, Type: typ}
-               params = append(params, field)
-               // Go spec: The scope of an identifier denoting a function
-               // parameter or result variable is the function body.
-               p.declare(field, nil, scope, ast.Var, idents...)
-               p.resolve(typ)
-               if !p.atComma("parameter list", token.RPAREN) {
-                       return
+       if len(list) == 0 {
+               return // not uncommon
+       }
+
+       // TODO(gri) parameter distribution and conversion to []*ast.Field
+       //           can be combined and made more efficient
+
+       // distribute parameter types
+       if named == 0 {
+               // all unnamed => found names are type names
+               for i := 0; i < len(list); i++ {
+                       par := &list[i]
+                       if typ := par.name; typ != nil {
+                               p.resolve(typ)
+                               par.typ = typ
+                               par.name = nil
+                       }
                }
-               p.next()
-               for p.tok != token.RPAREN && p.tok != token.EOF {
-                       idents := p.parseIdentList()
-                       typ := p.parseVarType(ellipsisOk)
-                       field := &ast.Field{Names: idents, Type: typ}
-                       params = append(params, field)
-                       // Go spec: The scope of an identifier denoting a function
-                       // parameter or result variable is the function body.
-                       p.declare(field, nil, scope, ast.Var, idents...)
-                       p.resolve(typ)
-                       if !p.atComma("parameter list", token.RPAREN) {
-                               break
+               if tparams {
+                       p.error(pos, "all type parameters must be named")
+               }
+       } else if named != len(list) {
+               // some named => all must be named
+               ok := true
+               var typ ast.Expr
+               for i := len(list) - 1; i >= 0; i-- {
+                       if par := &list[i]; par.typ != nil {
+                               typ = par.typ
+                               if par.name == nil {
+                                       ok = false
+                                       n := ast.NewIdent("_")
+                                       n.NamePos = typ.Pos() // correct position
+                                       par.name = n
+                               }
+                       } else if typ != nil {
+                               par.typ = typ
+                       } else {
+                               // par.typ == nil && typ == nil => we only have a par.name
+                               ok = false
+                               par.typ = &ast.BadExpr{From: par.name.Pos(), To: p.pos}
                        }
-                       p.next()
+               }
+               if !ok {
+                       if tparams {
+                               p.error(pos, "all type parameters must be named")
+                       } else {
+                               p.error(pos, "mixed named and unnamed parameters")
+                       }
+               }
+       }
+
+       // convert list []*ast.Field
+       if named == 0 {
+               // parameter list consists of types only
+               for _, par := range list {
+                       assert(par.typ != nil, "nil type in unnamed parameter list")
+                       params = append(params, &ast.Field{Type: par.typ})
                }
                return
        }
 
-       // Type { "," Type } (anonymous parameters)
-       params = make([]*ast.Field, len(list))
-       for i, typ := range list {
-               p.resolve(typ)
-               params[i] = &ast.Field{Type: typ}
+       // parameter list consists of named parameters with types
+       var names []*ast.Ident
+       var typ ast.Expr
+       addParams := func() {
+               assert(typ != nil, "nil type in named parameter list")
+               field := &ast.Field{Names: names, Type: typ}
+               // Go spec: The scope of an identifier denoting a function
+               // parameter or result variable is the function body.
+               p.declare(field, nil, scope, ast.Var, names...)
+               params = append(params, field)
+               names = nil
+       }
+       for _, par := range list {
+               if par.typ != typ {
+                       if len(names) > 0 {
+                               addParams()
+                       }
+                       typ = par.typ
+               }
+               names = append(names, par.name)
+       }
+       if len(names) > 0 {
+               addParams()
        }
        return
 }
 
-func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList {
+func (p *parser) parseParameters(scope *ast.Scope, acceptTParams bool) (tparams, params *ast.FieldList) {
        if p.trace {
                defer un(trace(p, "Parameters"))
        }
 
-       var params []*ast.Field
-       lparen := p.expect(token.LPAREN)
+       if p.mode&ParseTypeParams != 0 && acceptTParams && p.tok == token.LBRACK {
+               opening := p.pos
+               p.next()
+               // [T any](params) syntax
+               list := p.parseParameterList(scope, nil, token.RBRACK, p.parseParamDecl, true)
+               rbrack := p.expect(token.RBRACK)
+               tparams = &ast.FieldList{Opening: opening, List: list, Closing: rbrack}
+               // Type parameter lists must not be empty.
+               if tparams != nil && tparams.NumFields() == 0 {
+                       p.error(tparams.Closing, "empty type parameter list")
+                       tparams = nil // avoid follow-on errors
+               }
+       }
+
+       opening := p.expect(token.LPAREN)
+
+       var fields []*ast.Field
        if p.tok != token.RPAREN {
-               params = p.parseParameterList(scope, ellipsisOk)
+               fields = p.parseParameterList(scope, nil, token.RPAREN, p.parseParamDecl, false)
        }
+
        rparen := p.expect(token.RPAREN)
+       params = &ast.FieldList{Opening: opening, List: fields, Closing: rparen}
 
-       return &ast.FieldList{Opening: lparen, List: params, Closing: rparen}
+       return
 }
 
 func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
@@ -901,7 +1078,8 @@ func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
        }
 
        if p.tok == token.LPAREN {
-               return p.parseParameters(scope, false)
+               _, results := p.parseParameters(scope, false)
+               return results
        }
 
        typ := p.tryType()
@@ -914,17 +1092,6 @@ func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
        return nil
 }
 
-func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) {
-       if p.trace {
-               defer un(trace(p, "Signature"))
-       }
-
-       params = p.parseParameters(scope, true)
-       results = p.parseResult(scope)
-
-       return
-}
-
 func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
        if p.trace {
                defer un(trace(p, "FuncType"))
@@ -932,7 +1099,11 @@ func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
 
        pos := p.expect(token.FUNC)
        scope := ast.NewScope(p.topScope) // function scope
-       params, results := p.parseSignature(scope)
+       tparams, params := p.parseParameters(scope, true)
+       if tparams != nil {
+               p.error(tparams.Pos(), "function type cannot have type parameters")
+       }
+       results := p.parseResult(scope)
 
        return &ast.FuncType{Func: pos, Params: params, Results: results}, scope
 }
@@ -945,17 +1116,65 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
        doc := p.leadComment
        var idents []*ast.Ident
        var typ ast.Expr
-       x := p.parseTypeName()
-       if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
-               // method
-               idents = []*ast.Ident{ident}
-               scope := ast.NewScope(nil) // method scope
-               params, results := p.parseSignature(scope)
-               typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results}
+       x := p.parseTypeName(nil)
+       if ident, _ := x.(*ast.Ident); ident != nil {
+               switch {
+               case p.tok == token.LBRACK && p.mode&ParseTypeParams != 0:
+                       // generic method or embedded instantiated type
+                       lbrack := p.pos
+                       p.next()
+                       p.exprLev++
+                       x := p.parseExpr(true) // we don't know yet if we're a lhs or rhs expr
+                       p.exprLev--
+                       if name0, _ := x.(*ast.Ident); name0 != nil && p.tok != token.COMMA && p.tok != token.RBRACK {
+                               // generic method m[T any]
+                               scope := ast.NewScope(nil) // method scope
+                               list := p.parseParameterList(scope, name0, token.RBRACK, p.parseParamDecl, true)
+                               rbrack := p.expect(token.RBRACK)
+                               tparams := &ast.FieldList{Opening: lbrack, List: list, Closing: rbrack}
+                               // TODO(rfindley) refactor to share code with parseFuncType.
+                               _, params := p.parseParameters(scope, false)
+                               results := p.parseResult(scope)
+                               idents = []*ast.Ident{ident}
+                               typ = &ast.FuncType{Func: token.NoPos, TParams: tparams, Params: params, Results: results}
+                       } else {
+                               // embedded instantiated type
+                               // TODO(rfindley) should resolve all identifiers in x.
+                               list := []ast.Expr{x}
+                               if p.atComma("type argument list", token.RBRACK) {
+                                       p.exprLev++
+                                       for p.tok != token.RBRACK && p.tok != token.EOF {
+                                               list = append(list, p.parseType())
+                                               if !p.atComma("type argument list", token.RBRACK) {
+                                                       break
+                                               }
+                                               p.next()
+                                       }
+                                       p.exprLev--
+                               }
+                               rbrack := p.expectClosing(token.RBRACK, "type argument list")
+                               typ = &ast.CallExpr{Fun: ident, Lparen: lbrack, Args: list, Rparen: rbrack, Brackets: true}
+                       }
+               case p.tok == token.LPAREN:
+                       // ordinary method
+                       // TODO(rfindley) refactor to share code with parseFuncType.
+                       scope := ast.NewScope(nil) // method scope
+                       _, params := p.parseParameters(scope, false)
+                       results := p.parseResult(scope)
+                       idents = []*ast.Ident{ident}
+                       typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results}
+               default:
+                       // embedded type
+                       typ = x
+                       p.resolve(typ)
+               }
        } else {
-               // embedded interface
+               // embedded, possibly instantiated type
                typ = x
-               p.resolve(typ)
+               if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 {
+                       // embedded instantiated interface
+                       typ = p.parseTypeInstance(typ)
+               }
        }
        p.expectSemi() // call before accessing p.linecomment
 
@@ -974,9 +1193,23 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
        lbrace := p.expect(token.LBRACE)
        scope := ast.NewScope(nil) // interface scope
        var list []*ast.Field
-       for p.tok == token.IDENT {
-               list = append(list, p.parseMethodSpec(scope))
+       for p.tok == token.IDENT || p.mode&ParseTypeParams != 0 && p.tok == token.TYPE {
+               if p.tok == token.IDENT {
+                       list = append(list, p.parseMethodSpec(scope))
+               } else {
+                       // all types in a type list share the same field name "type"
+                       // (since type is a keyword, a Go program cannot have that field name)
+                       name := []*ast.Ident{{NamePos: p.pos, Name: "type"}}
+                       p.next()
+                       // add each type as a field named "type"
+                       for _, typ := range p.parseTypeList() {
+                               list = append(list, &ast.Field{Names: name, Type: typ})
+                       }
+                       p.expectSemi()
+               }
        }
+       // TODO(rfindley): the error produced here could be improved, since we could
+       // accept a identifier, 'type', or a '}' at this point.
        rbrace := p.expect(token.RBRACE)
 
        return &ast.InterfaceType{
@@ -1028,13 +1261,44 @@ func (p *parser) parseChanType() *ast.ChanType {
        return &ast.ChanType{Begin: pos, Arrow: arrow, Dir: dir, Value: value}
 }
 
+func (p *parser) parseTypeInstance(typ ast.Expr) ast.Expr {
+       if p.trace {
+               defer un(trace(p, "TypeInstance"))
+       }
+
+       opening := p.expect(token.LBRACK)
+
+       p.exprLev++
+       var list []ast.Expr
+       for p.tok != token.RBRACK && p.tok != token.EOF {
+               list = append(list, p.parseType())
+               if !p.atComma("type argument list", token.RBRACK) {
+                       break
+               }
+               p.next()
+       }
+       p.exprLev--
+
+       closing := p.expectClosing(token.RBRACK, "type argument list")
+
+       return &ast.CallExpr{Fun: typ, Lparen: opening, Args: list, Rparen: closing, Brackets: true}
+}
+
 // If the result is an identifier, it is not resolved.
 func (p *parser) tryIdentOrType() ast.Expr {
        switch p.tok {
        case token.IDENT:
-               return p.parseTypeName()
+               typ := p.parseTypeName(nil)
+               if p.tok == token.LBRACK && p.mode&ParseTypeParams != 0 {
+                       typ = p.parseTypeInstance(typ)
+               }
+               return typ
        case token.LBRACK:
-               return p.parseArrayType()
+               lbrack := p.expect(token.LBRACK)
+               alen := p.parseArrayLen()
+               p.expect(token.RBRACK)
+               elt := p.parseType()
+               return &ast.ArrayType{Lbrack: lbrack, Len: alen, Elt: elt}
        case token.STRUCT:
                return p.parseStructType()
        case token.MUL:
@@ -1169,7 +1433,7 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
                return p.parseFuncTypeOrLit()
        }
 
-       if typ := p.tryIdentOrType(); typ != nil {
+       if typ := p.tryIdentOrType(); typ != nil { // do not consume trailing type parameters
                // could be type for composite literal or conversion
                _, isIdent := typ.(*ast.Ident)
                assert(!isIdent, "type cannot be identifier")
@@ -1211,28 +1475,53 @@ func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
        return &ast.TypeAssertExpr{X: x, Type: typ, Lparen: lparen, Rparen: rparen}
 }
 
-func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
+func (p *parser) parseIndexOrSliceOrInstance(x ast.Expr) ast.Expr {
        if p.trace {
-               defer un(trace(p, "IndexOrSlice"))
+               defer un(trace(p, "parseIndexOrSliceOrInstance"))
        }
 
-       const N = 3 // change the 3 to 2 to disable 3-index slices
        lbrack := p.expect(token.LBRACK)
+       if p.tok == token.RBRACK {
+               // empty index, slice or index expressions are not permitted;
+               // accept them for parsing tolerance, but complain
+               p.errorExpected(p.pos, "operand")
+               p.next()
+               return x
+       }
        p.exprLev++
+
+       const N = 3 // change the 3 to 2 to disable 3-index slices
+       var args []ast.Expr
        var index [N]ast.Expr
        var colons [N - 1]token.Pos
        if p.tok != token.COLON {
-               index[0] = p.parseRhs()
+               // We can't know if we have an index expression or a type instantiation;
+               // so even if we see a (named) type we are not going to be in type context.
+               index[0] = p.parseRhsOrType()
        }
        ncolons := 0
-       for p.tok == token.COLON && ncolons < len(colons) {
-               colons[ncolons] = p.pos
-               ncolons++
-               p.next()
-               if p.tok != token.COLON && p.tok != token.RBRACK && p.tok != token.EOF {
-                       index[ncolons] = p.parseRhs()
+       switch p.tok {
+       case token.COLON:
+               // slice expression
+               for p.tok == token.COLON && ncolons < len(colons) {
+                       colons[ncolons] = p.pos
+                       ncolons++
+                       p.next()
+                       if p.tok != token.COLON && p.tok != token.RBRACK && p.tok != token.EOF {
+                               index[ncolons] = p.parseRhs()
+                       }
+               }
+       case token.COMMA:
+               // instance expression
+               args = append(args, index[0])
+               for p.tok == token.COMMA {
+                       p.next()
+                       if p.tok != token.RBRACK && p.tok != token.EOF {
+                               args = append(args, p.parseType())
+                       }
                }
        }
+
        p.exprLev--
        rbrack := p.expect(token.RBRACK)
 
@@ -1255,7 +1544,13 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
                return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: index[0], High: index[1], Max: index[2], Slice3: slice3, Rbrack: rbrack}
        }
 
-       return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: index[0], Rbrack: rbrack}
+       if len(args) == 0 {
+               // index expression
+               return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: index[0], Rbrack: rbrack}
+       }
+
+       // instance expression
+       return &ast.CallExpr{Fun: x, Lparen: lbrack, Args: args, Rparen: rbrack, Brackets: true}
 }
 
 func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
@@ -1404,45 +1699,6 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
        return x
 }
 
-// isTypeName reports whether x is a (qualified) TypeName.
-func isTypeName(x ast.Expr) bool {
-       switch t := x.(type) {
-       case *ast.BadExpr:
-       case *ast.Ident:
-       case *ast.SelectorExpr:
-               _, isIdent := t.X.(*ast.Ident)
-               return isIdent
-       default:
-               return false // all other nodes are not type names
-       }
-       return true
-}
-
-// isLiteralType reports whether x is a legal composite literal type.
-func isLiteralType(x ast.Expr) bool {
-       switch t := x.(type) {
-       case *ast.BadExpr:
-       case *ast.Ident:
-       case *ast.SelectorExpr:
-               _, isIdent := t.X.(*ast.Ident)
-               return isIdent
-       case *ast.ArrayType:
-       case *ast.StructType:
-       case *ast.MapType:
-       default:
-               return false // all other nodes are not legal composite literal types
-       }
-       return true
-}
-
-// If x is of the form *T, deref returns T, otherwise it returns x.
-func deref(x ast.Expr) ast.Expr {
-       if p, isPtr := x.(*ast.StarExpr); isPtr {
-               x = p.X
-       }
-       return x
-}
-
 // If x is of the form (T), unparen returns unparen(T), otherwise it returns x.
 func unparen(x ast.Expr) ast.Expr {
        if p, isParen := x.(*ast.ParenExpr); isParen {
@@ -1470,13 +1726,12 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
 }
 
 // If lhs is set and the result is an identifier, it is not resolved.
-func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr {
+func (p *parser) parsePrimaryExpr(lhs bool) (x ast.Expr) {
        if p.trace {
                defer un(trace(p, "PrimaryExpr"))
        }
 
-       x := p.parseOperand(lhs)
-L:
+       x = p.parseOperand(lhs)
        for {
                switch p.tok {
                case token.PERIOD:
@@ -1500,28 +1755,48 @@ L:
                        if lhs {
                                p.resolve(x)
                        }
-                       x = p.parseIndexOrSlice(p.checkExpr(x))
+                       x = p.parseIndexOrSliceOrInstance(p.checkExpr(x))
                case token.LPAREN:
                        if lhs {
                                p.resolve(x)
                        }
                        x = p.parseCallOrConversion(p.checkExprOrType(x))
                case token.LBRACE:
-                       if isLiteralType(x) && (p.exprLev >= 0 || !isTypeName(x)) {
-                               if lhs {
-                                       p.resolve(x)
+                       // operand may have returned a parenthesized complit
+                       // type; accept it but complain if we have a complit
+                       t := unparen(x)
+                       // determine if '{' belongs to a composite literal or a block statement
+                       switch t := t.(type) {
+                       case *ast.BadExpr, *ast.Ident, *ast.SelectorExpr:
+                               if p.exprLev < 0 {
+                                       return
                                }
-                               x = p.parseLiteralValue(x)
-                       } else {
-                               break L
+                               // x is possibly a composite literal type
+                       case *ast.CallExpr:
+                               if !t.Brackets || p.exprLev < 0 {
+                                       return
+                               }
+                               // x is possibly a composite literal type
+                       case *ast.IndexExpr:
+                               if p.exprLev < 0 {
+                                       return
+                               }
+                               // x is possibly a composite literal type
+                       case *ast.ArrayType, *ast.StructType, *ast.MapType:
+                               // x is a composite literal type
+                       default:
+                               return
+                       }
+                       if t != x {
+                               p.error(t.Pos(), "cannot parenthesize type in composite literal")
+                               // already progressed, no need to advance
                        }
+                       x = p.parseLiteralValue(x)
                default:
-                       break L
+                       return
                }
                lhs = false // no need to try to resolve again
        }
-
-       return x
 }
 
 // If lhs is set and the result is an identifier, it is not resolved.
@@ -1846,14 +2121,14 @@ func (p *parser) parseIfHeader() (init ast.Stmt, cond ast.Expr) {
        }
        // p.tok != token.LBRACE
 
-       outer := p.exprLev
+       prevLev := p.exprLev
        p.exprLev = -1
 
        if p.tok != token.SEMICOLON {
                // accept potential variable declaration but complain
                if p.tok == token.VAR {
                        p.next()
-                       p.error(p.pos, fmt.Sprintf("var declaration not allowed in 'IF' initializer"))
+                       p.error(p.pos, "var declaration not allowed in 'IF' initializer")
                }
                init, _ = p.parseSimpleStmt(basic)
        }
@@ -1894,7 +2169,7 @@ func (p *parser) parseIfHeader() (init ast.Stmt, cond ast.Expr) {
                cond = &ast.BadExpr{From: p.pos, To: p.pos}
        }
 
-       p.exprLev = outer
+       p.exprLev = prevLev
        return
 }
 
@@ -2275,7 +2550,7 @@ func (p *parser) parseStmt() (s ast.Stmt) {
 // ----------------------------------------------------------------------------
 // Declarations
 
-type parseSpecFunction func(doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec
+type parseSpecFunction func(doc *ast.CommentGroup, pos token.Pos, keyword token.Token, iota int) ast.Spec
 
 func isValidImport(lit string) bool {
        const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
@@ -2288,7 +2563,7 @@ func isValidImport(lit string) bool {
        return s != ""
 }
 
-func (p *parser) parseImportSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.Spec {
+func (p *parser) parseImportSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token, _ int) ast.Spec {
        if p.trace {
                defer un(trace(p, "ImportSpec"))
        }
@@ -2327,7 +2602,7 @@ func (p *parser) parseImportSpec(doc *ast.CommentGroup, _ token.Token, _ int) as
        return spec
 }
 
-func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec {
+func (p *parser) parseValueSpec(doc *ast.CommentGroup, _ token.Pos, keyword token.Token, iota int) ast.Spec {
        if p.trace {
                defer un(trace(p, keyword.String()+"Spec"))
        }
@@ -2374,7 +2649,21 @@ func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota
        return spec
 }
 
-func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.Spec {
+func (p *parser) parseGenericType(spec *ast.TypeSpec, openPos token.Pos, name0 *ast.Ident, closeTok token.Token) {
+       p.openScope()
+       list := p.parseParameterList(p.topScope, name0, closeTok, p.parseParamDecl, true)
+       closePos := p.expect(closeTok)
+       spec.TParams = &ast.FieldList{Opening: openPos, List: list, Closing: closePos}
+       // Type alias cannot have type parameters. Accept them for robustness but complain.
+       if p.tok == token.ASSIGN {
+               p.error(p.pos, "generic type cannot be alias")
+               p.next()
+       }
+       spec.Type = p.parseType()
+       p.closeScope()
+}
+
+func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token, _ int) ast.Spec {
        if p.trace {
                defer un(trace(p, "TypeSpec"))
        }
@@ -2387,11 +2676,44 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.
        // (Global identifiers are resolved in a separate phase after parsing.)
        spec := &ast.TypeSpec{Doc: doc, Name: ident}
        p.declare(spec, nil, p.topScope, ast.Typ, ident)
-       if p.tok == token.ASSIGN {
-               spec.Assign = p.pos
+
+       switch p.tok {
+       case token.LBRACK:
+               lbrack := p.pos
                p.next()
+               if p.tok == token.IDENT {
+                       // array type or generic type [T any]
+                       p.exprLev++
+                       x := p.parseExpr(true) // we don't know yet if we're a lhs or rhs expr
+                       p.exprLev--
+                       if name0, _ := x.(*ast.Ident); p.mode&ParseTypeParams != 0 && name0 != nil && p.tok != token.RBRACK {
+                               // generic type [T any];
+                               p.parseGenericType(spec, lbrack, name0, token.RBRACK)
+                       } else {
+                               // array type
+                               // TODO(rfindley) should resolve all identifiers in x.
+                               p.expect(token.RBRACK)
+                               elt := p.parseType()
+                               spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: x, Elt: elt}
+                       }
+               } else {
+                       // array type
+                       alen := p.parseArrayLen()
+                       p.expect(token.RBRACK)
+                       elt := p.parseType()
+                       spec.Type = &ast.ArrayType{Lbrack: lbrack, Len: alen, Elt: elt}
+               }
+
+       default:
+               // no type parameters
+               if p.tok == token.ASSIGN {
+                       // type alias
+                       spec.Assign = p.pos
+                       p.next()
+               }
+               spec.Type = p.parseType()
        }
-       spec.Type = p.parseType()
+
        p.expectSemi() // call before accessing p.linecomment
        spec.Comment = p.lineComment
 
@@ -2411,12 +2733,12 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
                lparen = p.pos
                p.next()
                for iota := 0; p.tok != token.RPAREN && p.tok != token.EOF; iota++ {
-                       list = append(list, f(p.leadComment, keyword, iota))
+                       list = append(list, f(p.leadComment, pos, keyword, iota))
                }
                rparen = p.expect(token.RPAREN)
                p.expectSemi()
        } else {
-               list = append(list, f(nil, keyword, 0))
+               list = append(list, f(nil, pos, keyword, 0))
        }
 
        return &ast.GenDecl{
@@ -2440,12 +2762,13 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
 
        var recv *ast.FieldList
        if p.tok == token.LPAREN {
-               recv = p.parseParameters(scope, false)
+               _, recv = p.parseParameters(scope, false)
        }
 
        ident := p.parseIdent()
 
-       params, results := p.parseSignature(scope)
+       tparams, params := p.parseParameters(scope, true)
+       results := p.parseResult(scope)
 
        var body *ast.BlockStmt
        if p.tok == token.LBRACE {
@@ -2469,6 +2792,7 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
                Name: ident,
                Type: &ast.FuncType{
                        Func:    pos,
+                       TParams: tparams,
                        Params:  params,
                        Results: results,
                },
index 49bb681e09e66ea275934c5d85dd2f95925fb4b4..3676c275597cdb6221cc66f36d3343b16a82ee01 100644 (file)
@@ -48,12 +48,101 @@ var valids = []string{
        `package p; var _ = map[*P]int{&P{}:0, {}:1}`,
        `package p; type T = int`,
        `package p; type (T = p.T; _ = struct{}; x = *T)`,
+       `package p; type T (*int)`,
+       `package p; type _ struct{ ((int)) }`,
+       `package p; type _ struct{ (*(int)) }`,
+       `package p; type _ struct{ ([]byte) }`, // disallowed by type-checker
+       `package p; var _ = func()T(nil)`,
+       `package p; func _(T (P))`,
+       `package p; func _(T []E)`,
+       `package p; func _(T [P]E)`,
+       `package p; type _ [A+B]struct{}`,
+       `package p; func (R) _()`,
+       `package p; type _ struct{ f [n]E }`,
+       `package p; type _ struct{ f [a+b+c+d]E }`,
+       `package p; type I1 interface{}; type I2 interface{ I1 }`,
+}
+
+// validWithTParamsOnly holds source code examples that are valid if
+// ParseTypeParams is set, but invalid if not. When checking with the
+// ParseTypeParams set, errors are ignored.
+var validWithTParamsOnly = []string{
+       `package p; type _ []T[ /* ERROR "expected ';', found '\['" */ int]`,
+       `package p; type T[P any /* ERROR "expected ']', found any" */ ] struct { P }`,
+       `package p; type T[P comparable /* ERROR "expected ']', found comparable" */ ] struct { P }`,
+       `package p; type T[P comparable /* ERROR "expected ']', found comparable" */ [P]] struct { P }`,
+       `package p; type T[P1, /* ERROR "expected ']', found ','" */ P2 any] struct { P1; f []P2 }`,
+       `package p; func _[ /* ERROR "expected '\(', found '\['" */ T any]()()`,
+       `package p; func _(T (P))`,
+       `package p; func f[ /* ERROR "expected '\(', found '\['" */ A, B any](); func _() { _ = f[int, int] }`,
+       `package p; func _(x /* ERROR "mixed named and unnamed parameters" */ T[P1, P2, P3])`,
+       `package p; func _(x /* ERROR "mixed named and unnamed parameters" */ p.T[Q])`,
+       `package p; func _(p.T[ /* ERROR "missing ',' in parameter list" */ Q])`,
+       `package p; type _[A interface /* ERROR "expected ']', found 'interface'" */ {},] struct{}`,
+       `package p; type _[A interface /* ERROR "expected ']', found 'interface'" */ {}] struct{}`,
+       `package p; type _[A, /* ERROR "expected ']', found ','" */  B any,] struct{}`,
+       `package p; type _[A, /* ERROR "expected ']', found ','" */ B any] struct{}`,
+       `package p; type _[A any /* ERROR "expected ']', found any" */,] struct{}`,
+       `package p; type _[A any /* ERROR "expected ']', found any" */ ]struct{}`,
+       `package p; type _[A any /* ERROR "expected ']', found any" */ ] struct{ A }`,
+       `package p; func _[ /* ERROR "expected '\(', found '\['" */ T any]()`,
+       `package p; func _[ /* ERROR "expected '\(', found '\['" */ T any](x T)`,
+       `package p; func _[ /* ERROR "expected '\(', found '\['" */ T1, T2 any](x T)`,
+       `package p; func _[ /* ERROR "expected '\(', found '\['" */ A, B any](a A) B`,
+       `package p; func _[ /* ERROR "expected '\(', found '\['" */ A, B C](a A) B`,
+       `package p; func _[ /* ERROR "expected '\(', found '\['" */ A, B C[A, B]](a A) B`,
+       `package p; func (T) _[ /* ERROR "expected '\(', found '\['" */ A, B any](a A) B`,
+       `package p; func (T) _[ /* ERROR "expected '\(', found '\['" */ A, B C](a A) B`,
+       `package p; func (T) _[ /* ERROR "expected '\(', found '\['" */ A, B C[A, B]](a A) B`,
+       `package p; type _[A, /* ERROR "expected ']', found ','" */ B any] interface { _(a A) B }`,
+       `package p; type _[A, /* ERROR "expected ']', found ','" */ B C[A, B]] interface { _(a A) B }`,
+       `package p; func _[ /* ERROR "expected '\(', found '\['" */ T1, T2 interface{}](x T1) T2`,
+       `package p; func _[ /* ERROR "expected '\(', found '\['" */ T1 interface{ m() }, T2, T3 interface{}](x T1, y T3) T2`,
+       `package p; var _ = [ /* ERROR "expected expression" */ ]T[int]{}`,
+       `package p; var _ = [ /* ERROR "expected expression" */ 10]T[int]{}`,
+       `package p; var _ = func /* ERROR "expected expression" */ ()T[int]{}`,
+       `package p; var _ = map /* ERROR "expected expression" */ [T[int]]T[int]{}`,
+       `package p; var _ = chan /* ERROR "expected expression" */ T[int](x)`,
+       `package p; func _(_ T[ /* ERROR "missing ',' in parameter list" */ P], T P) T[P]`,
+       `package p; var _ T[ /* ERROR "expected ';', found '\['" */ chan int]`,
+
+       // TODO(rfindley) this error message could be improved.
+       `package p; func (_ /* ERROR "mixed named and unnamed parameters" */ R[P]) _[T any](x T)`,
+       `package p; func (_ /* ERROR "mixed named and unnamed parameters" */ R[ P, Q]) _[T1, T2 any](x T)`,
+
+       `package p; func (R[P] /* ERROR "missing element type" */ ) _[T any]()`,
+       `package p; func _(T[P] /* ERROR "missing element type" */ )`,
+       `package p; func _(T[P1, /* ERROR "expected ']', found ','" */ P2, P3 ])`,
+       `package p; func _(T[P] /* ERROR "missing element type" */ ) T[P]`,
+       `package p; type _ struct{ T[P] /* ERROR "missing element type" */ }`,
+       `package p; type _ struct{ T[struct /* ERROR "expected expression" */ {a, b, c int}] }`,
+       `package p; type _ interface{type /* ERROR "expected '}', found 'type'" */ int}`,
+       `package p; type _ interface{type /* ERROR "expected '}', found 'type'" */ int, float32; type bool; m(); type string;}`,
+       `package p; type I1[T any /* ERROR "expected ']', found any" */ ] interface{}; type I2 interface{ I1[int] }`,
+       `package p; type I1[T any /* ERROR "expected ']', found any" */ ] interface{}; type I2[T any] interface{ I1[T] }`,
+       `package p; type _ interface { f[ /* ERROR "expected ';', found '\['" */ T any]() }`,
 }
 
 func TestValid(t *testing.T) {
-       for _, src := range valids {
-               checkErrors(t, src, src)
-       }
+       t.Run("no tparams", func(t *testing.T) {
+               for _, src := range valids {
+                       checkErrors(t, src, src, DeclarationErrors|AllErrors, false)
+               }
+       })
+       t.Run("tparams", func(t *testing.T) {
+               for _, src := range valids {
+                       checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, false)
+               }
+               for _, src := range validWithTParamsOnly {
+                       checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, false)
+               }
+       })
+}
+
+// TestSingle is useful to track down a problem with a single short test program.
+func TestSingle(t *testing.T) {
+       const src = `package p; var _ = T[P]{}`
+       checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, true)
 }
 
 var invalids = []string{
@@ -79,7 +168,6 @@ var invalids = []string{
        `package p; var a = chan /* ERROR "expected expression" */ int;`,
        `package p; var a = []int{[ /* ERROR "expected expression" */ ]int};`,
        `package p; var a = ( /* ERROR "expected expression" */ []int);`,
-       `package p; var a = a[[ /* ERROR "expected expression" */ ]int:[]int];`,
        `package p; var a = <- /* ERROR "expected expression" */ chan int;`,
        `package p; func f() { select { case _ <- chan /* ERROR "expected expression" */ int: } };`,
        `package p; func f() { _ = (<-<- /* ERROR "expected 'chan'" */ chan int)(nil) };`,
@@ -102,7 +190,14 @@ var invalids = []string{
        `package p; func f() { go f /* ERROR HERE "function must be invoked" */ }`,
        `package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`,
        `package p; func f() { go func() { func() { f(x func /* ERROR "missing ','" */ (){}) } } }`,
-       `package p; func f(x func(), u v func /* ERROR "missing ','" */ ()){}`,
+       `package p; func _() (type /* ERROR "found 'type'" */ T)(T)`,
+       `package p; func (type /* ERROR "found 'type'" */ T)(T) _()`,
+       `package p; type _[A+B, /* ERROR "expected ']'" */ ] int`,
+
+       // TODO: this error should be positioned on the ':'
+       `package p; var a = a[[]int:[ /* ERROR "expected expression" */ ]int];`,
+       // TODO: the compiler error is better here: "cannot parenthesize embedded type"
+       `package p; type I1 interface{}; type I2 interface{ (/* ERROR "expected '}', found '\('" */ I1) }`,
 
        // issue 8656
        `package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`,
@@ -118,19 +213,58 @@ var invalids = []string{
        `package p; var _ = struct { x int, /* ERROR "expected ';', found ','" */ y float }{};`,
 
        // issue 11611
-       `package p; type _ struct { int, } /* ERROR "expected type, found '}'" */ ;`,
+       `package p; type _ struct { int, } /* ERROR "expected 'IDENT', found '}'" */ ;`,
        `package p; type _ struct { int, float } /* ERROR "expected type, found '}'" */ ;`,
-       `package p; type _ struct { ( /* ERROR "expected anonymous field" */ int) };`,
-       `package p; func _()(x, y, z ... /* ERROR "expected '\)', found '...'" */ int){}`,
-       `package p; func _()(... /* ERROR "expected type, found '...'" */ int){}`,
 
        // issue 13475
        `package p; func f() { if true {} else ; /* ERROR "expected if statement or block" */ }`,
        `package p; func f() { if true {} else defer /* ERROR "expected if statement or block" */ f() }`,
 }
 
+// invalidNoTParamErrs holds invalid source code examples annotated with the
+// error messages produced when ParseTypeParams is not set.
+var invalidNoTParamErrs = []string{
+       `package p; type _[_ any /* ERROR "expected ']', found any" */ ] int; var _ = T[]{}`,
+       `package p; type T[P any /* ERROR "expected ']', found any" */ ] = T0`,
+       `package p; var _ func[ /* ERROR "expected '\(', found '\['" */ T any](T)`,
+       `package p; func _[ /* ERROR "expected '\(', found '\['" */ ]()`,
+       `package p; type _[A, /* ERROR "expected ']', found ','" */] struct{ A }`,
+       `package p; func _[ /* ERROR "expected '\(', found '\['" */ type P, *Q interface{}]()`,
+}
+
+// invalidTParamErrs holds invalid source code examples annotated with the
+// error messages produced when ParseTypeParams is set.
+var invalidTParamErrs = []string{
+       `package p; type _[_ any] int; var _ = T[] /* ERROR "expected operand" */ {}`,
+       `package p; type T[P any] = /* ERROR "cannot be alias" */ T0`,
+       `package p; var _ func[ /* ERROR "cannot have type parameters" */ T any](T)`,
+       `package p; func _[]/* ERROR "empty type parameter list" */()`,
+
+       // TODO(rfindley) a better location would be after the ']'
+       `package p; type _[A/* ERROR "all type parameters must be named" */,] struct{ A }`,
+
+       // TODO(rfindley) this error is confusing.
+       `package p; func _[type /* ERROR "all type parameters must be named" */P, *Q interface{}]()`,
+}
+
 func TestInvalid(t *testing.T) {
-       for _, src := range invalids {
-               checkErrors(t, src, src)
-       }
+       t.Run("no tparams", func(t *testing.T) {
+               for _, src := range invalids {
+                       checkErrors(t, src, src, DeclarationErrors|AllErrors, true)
+               }
+               for _, src := range validWithTParamsOnly {
+                       checkErrors(t, src, src, DeclarationErrors|AllErrors, true)
+               }
+               for _, src := range invalidNoTParamErrs {
+                       checkErrors(t, src, src, DeclarationErrors|AllErrors, true)
+               }
+       })
+       t.Run("tparams", func(t *testing.T) {
+               for _, src := range invalids {
+                       checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, true)
+               }
+               for _, src := range invalidTParamErrs {
+                       checkErrors(t, src, src, DeclarationErrors|AllErrors|ParseTypeParams, true)
+               }
+       })
 }
diff --git a/src/go/parser/testdata/chans.go2 b/src/go/parser/testdata/chans.go2
new file mode 100644 (file)
index 0000000..fad2bce
--- /dev/null
@@ -0,0 +1,62 @@
+package chans
+
+import "runtime"
+
+// Ranger returns a Sender and a Receiver. The Receiver provides a
+// Next method to retrieve values. The Sender provides a Send method
+// to send values and a Close method to stop sending values. The Next
+// method indicates when the Sender has been closed, and the Send
+// method indicates when the Receiver has been freed.
+//
+// This is a convenient way to exit a goroutine sending values when
+// the receiver stops reading them.
+func Ranger[T any]() (*Sender[T], *Receiver[T]) {
+       c := make(chan T)
+       d := make(chan bool)
+       s := &Sender[T]{values: c, done: d}
+       r := &Receiver[T]{values: c, done: d}
+       runtime.SetFinalizer(r, r.finalize)
+       return s, r
+}
+
+// A sender is used to send values to a Receiver.
+type Sender[T any] struct {
+       values chan<- T
+       done <-chan bool
+}
+
+// Send sends a value to the receiver. It returns whether any more
+// values may be sent; if it returns false the value was not sent.
+func (s *Sender[T]) Send(v T) bool {
+       select {
+       case s.values <- v:
+               return true
+       case <-s.done:
+               return false
+       }
+}
+
+// Close tells the receiver that no more values will arrive.
+// After Close is called, the Sender may no longer be used.
+func (s *Sender[T]) Close() {
+       close(s.values)
+}
+
+// A Receiver receives values from a Sender.
+type Receiver[T any] struct {
+       values <-chan T
+       done chan<- bool
+}
+
+// Next returns the next value from the channel. The bool result
+// indicates whether the value is valid, or whether the Sender has
+// been closed and no more values will be received.
+func (r *Receiver[T]) Next() (T, bool) {
+       v, ok := <-r.values
+       return v, ok
+}
+
+// finalize is a finalizer for the receiver.
+func (r *Receiver[T]) finalize() {
+       close(r.done)
+}
diff --git a/src/go/parser/testdata/linalg.go2 b/src/go/parser/testdata/linalg.go2
new file mode 100644 (file)
index 0000000..fba0d02
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright 2019 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 linalg
+
+import "math"
+
+// Numeric is type bound that matches any numeric type.
+// It would likely be in a constraints package in the standard library.
+type Numeric interface {
+       type int, int8, int16, int32, int64,
+               uint, uint8, uint16, uint32, uint64, uintptr,
+               float32, float64,
+               complex64, complex128
+}
+
+func DotProduct[T Numeric](s1, s2 []T) T {
+       if len(s1) != len(s2) {
+               panic("DotProduct: slices of unequal length")
+       }
+       var r T
+       for i := range s1 {
+               r += s1[i] * s2[i]
+       }
+       return r
+}
+
+// NumericAbs matches numeric types with an Abs method.
+type NumericAbs[T any] interface {
+       Numeric
+
+       Abs() T
+}
+
+// AbsDifference computes the absolute value of the difference of
+// a and b, where the absolute value is determined by the Abs method.
+func AbsDifference[T NumericAbs](a, b T) T {
+       d := a - b
+       return d.Abs()
+}
+
+// OrderedNumeric is a type bound that matches numeric types that support the < operator.
+type OrderedNumeric interface {
+       type int, int8, int16, int32, int64,
+               uint, uint8, uint16, uint32, uint64, uintptr,
+               float32, float64
+}
+
+// Complex is a type bound that matches the two complex types, which do not have a < operator.
+type Complex interface {
+       type complex64, complex128
+}
+
+// OrderedAbs is a helper type that defines an Abs method for
+// ordered numeric types.
+type OrderedAbs[T OrderedNumeric] T
+
+func (a OrderedAbs[T]) Abs() OrderedAbs[T] {
+       if a < 0 {
+               return -a
+       }
+       return a
+}
+
+// ComplexAbs is a helper type that defines an Abs method for
+// complex types.
+type ComplexAbs[T Complex] T
+
+func (a ComplexAbs[T]) Abs() ComplexAbs[T] {
+       r := float64(real(a))
+       i := float64(imag(a))
+       d := math.Sqrt(r * r + i * i)
+       return ComplexAbs[T](complex(d, 0))
+}
+
+func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
+       return T(AbsDifference(OrderedAbs[T](a), OrderedAbs[T](b)))
+}
+
+func ComplexAbsDifference[T Complex](a, b T) T {
+       return T(AbsDifference(ComplexAbs[T](a), ComplexAbs[T](b)))
+}
diff --git a/src/go/parser/testdata/map.go2 b/src/go/parser/testdata/map.go2
new file mode 100644 (file)
index 0000000..74c79ae
--- /dev/null
@@ -0,0 +1,109 @@
+// Package orderedmap provides an ordered map, implemented as a binary tree.
+package orderedmap
+
+import "chans"
+
+// Map is an ordered map.
+type Map[K, V any] struct {
+       root    *node[K, V]
+       compare func(K, K) int
+}
+
+// node is the type of a node in the binary tree.
+type node[K, V any] struct {
+       key         K
+       val         V
+       left, right *node[K, V]
+}
+
+// New returns a new map.
+func New[K, V any](compare func(K, K) int) *Map[K, V] {
+        return &Map[K, V]{compare: compare}
+}
+
+// find looks up key in the map, and returns either a pointer
+// to the node holding key, or a pointer to the location where
+// such a node would go.
+func (m *Map[K, V]) find(key K) **node[K, V] {
+       pn := &m.root
+       for *pn != nil {
+               switch cmp := m.compare(key, (*pn).key); {
+               case cmp < 0:
+                       pn = &(*pn).left
+               case cmp > 0:
+                       pn = &(*pn).right
+               default:
+                       return pn
+               }
+       }
+       return pn
+}
+
+// Insert inserts a new key/value into the map.
+// If the key is already present, the value is replaced.
+// Returns true if this is a new key, false if already present.
+func (m *Map[K, V]) Insert(key K, val V) bool {
+       pn := m.find(key)
+       if *pn != nil {
+               (*pn).val = val
+               return false
+       }
+        *pn = &node[K, V]{key: key, val: val}
+       return true
+}
+
+// Find returns the value associated with a key, or zero if not present.
+// The found result reports whether the key was found.
+func (m *Map[K, V]) Find(key K) (V, bool) {
+       pn := m.find(key)
+       if *pn == nil {
+               var zero V // see the discussion of zero values, above
+               return zero, false
+       }
+       return (*pn).val, true
+}
+
+// keyValue is a pair of key and value used when iterating.
+type keyValue[K, V any] struct {
+       key K
+       val V
+}
+
+// InOrder returns an iterator that does an in-order traversal of the map.
+func (m *Map[K, V]) InOrder() *Iterator[K, V] {
+       sender, receiver := chans.Ranger[keyValue[K, V]]()
+       var f func(*node[K, V]) bool
+       f = func(n *node[K, V]) bool {
+               if n == nil {
+                       return true
+               }
+               // Stop sending values if sender.Send returns false,
+               // meaning that nothing is listening at the receiver end.
+               return f(n.left) &&
+                        // TODO
+                       // sender.Send(keyValue[K, V]{n.key, n.val}) &&
+                       f(n.right)
+       }
+       go func() {
+               f(m.root)
+               sender.Close()
+       }()
+       return &Iterator{receiver}
+}
+
+// Iterator is used to iterate over the map.
+type Iterator[K, V any] struct {
+       r *chans.Receiver[keyValue[K, V]]
+}
+
+// Next returns the next key and value pair, and a boolean indicating
+// whether they are valid or whether we have reached the end.
+func (it *Iterator[K, V]) Next() (K, V, bool) {
+       keyval, ok := it.r.Next()
+       if !ok {
+               var zerok K
+               var zerov V
+               return zerok, zerov, false
+       }
+       return keyval.key, keyval.val, true
+}
diff --git a/src/go/parser/testdata/metrics.go2 b/src/go/parser/testdata/metrics.go2
new file mode 100644 (file)
index 0000000..ef1c66b
--- /dev/null
@@ -0,0 +1,58 @@
+package metrics
+
+import "sync"
+
+type Metric1[T comparable] struct {
+       mu sync.Mutex
+       m  map[T]int
+}
+
+func (m *Metric1[T]) Add(v T) {
+       m.mu.Lock()
+       defer m.mu.Unlock()
+       if m.m == nil {
+               m.m = make(map[T]int)
+       }
+       m[v]++
+}
+
+type key2[T1, T2 comparable] struct {
+       f1 T1
+       f2 T2
+}
+
+type Metric2[T1, T2 cmp2] struct {
+       mu sync.Mutex
+       m  map[key2[T1, T2]]int
+}
+
+func (m *Metric2[T1, T2]) Add(v1 T1, v2 T2) {
+       m.mu.Lock()
+       defer m.mu.Unlock()
+       if m.m == nil {
+               m.m = make(map[key2[T1, T2]]int)
+       }
+       m[key[T1, T2]{v1, v2}]++
+}
+
+type key3[T1, T2, T3 comparable] struct {
+       f1 T1
+       f2 T2
+       f3 T3
+}
+
+type Metric3[T1, T2, T3 comparable] struct {
+       mu sync.Mutex
+       m  map[key3[T1, T2, T3]]int
+}
+
+func (m *Metric3[T1, T2, T3]) Add(v1 T1, v2 T2, v3 T3) {
+       m.mu.Lock()
+       defer m.mu.Unlock()
+       if m.m == nil {
+               m.m = make(map[key3]int)
+       }
+       m[key[T1, T2, T3]{v1, v2, v3}]++
+}
+
+// Repeat for the maximum number of permitted arguments.
diff --git a/src/go/parser/testdata/set.go2 b/src/go/parser/testdata/set.go2
new file mode 100644 (file)
index 0000000..0da6377
--- /dev/null
@@ -0,0 +1,31 @@
+// Package set implements sets of any type.
+package set
+
+type Set[Elem comparable] map[Elem]struct{}
+
+func Make[Elem comparable]() Set[Elem] {
+       return make(Set(Elem))
+}
+
+func (s Set[Elem]) Add(v Elem) {
+       s[v] = struct{}{}
+}
+
+func (s Set[Elem]) Delete(v Elem) {
+       delete(s, v)
+}
+
+func (s Set[Elem]) Contains(v Elem) bool {
+       _, ok := s[v]
+       return ok
+}
+
+func (s Set[Elem]) Len() int {
+       return len(s)
+}
+
+func (s Set[Elem]) Iterate(f func(Elem)) {
+       for v := range s {
+               f(v)
+       }
+}
diff --git a/src/go/parser/testdata/slices.go2 b/src/go/parser/testdata/slices.go2
new file mode 100644 (file)
index 0000000..e060212
--- /dev/null
@@ -0,0 +1,31 @@
+// Package slices implements various slice algorithms.
+package slices
+
+// Map turns a []T1 to a []T2 using a mapping function.
+func Map[T1, T2 any](s []T1, f func(T1) T2) []T2 {
+       r := make([]T2, len(s))
+       for i, v := range s {
+               r[i] = f(v)
+       }
+       return r
+}
+
+// Reduce reduces a []T1 to a single value using a reduction function.
+func Reduce[T1, T2 any](s []T1, initializer T2, f func(T2, T1) T2) T2 {
+       r := initializer
+       for _, v := range s {
+               r = f(r, v)
+       }
+       return r
+}
+
+// Filter filters values from a slice using a filter function.
+func Filter[T any](s []T, f func(T) bool) []T {
+       var r []T
+       for _, v := range s {
+               if f(v) {
+                       r = append(r, v)
+               }
+       }
+       return r
+}
diff --git a/src/go/parser/testdata/sort.go2 b/src/go/parser/testdata/sort.go2
new file mode 100644 (file)
index 0000000..88be79f
--- /dev/null
@@ -0,0 +1,27 @@
+package sort
+
+type orderedSlice[Elem comparable] []Elem
+
+func (s orderedSlice[Elem]) Len() int           { return len(s) }
+func (s orderedSlice[Elem]) Less(i, j int) bool { return s[i] < s[j] }
+func (s orderedSlice[Elem]) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+
+// OrderedSlice sorts the slice s in ascending order.
+// The elements of s must be ordered using the < operator.
+func OrderedSlice[Elem comparable](s []Elem) {
+       sort.Sort(orderedSlice[Elem](s))
+}
+
+type sliceFn[Elem any] struct {
+       s []Elem
+       f func(Elem, Elem) bool
+}
+
+func (s sliceFn[Elem]) Len() int           { return len(s.s) }
+func (s sliceFn[Elem]) Less(i, j int) bool { return s.f(s.s[i], s.s[j]) }
+func (s sliceFn[Elem]) Swap(i, j int)      { s.s[i], s.s[j] = s.s[j], s.s[i] }
+
+// SliceFn sorts the slice s according to the function f.
+func SliceFn[Elem any](s []Elem, f func(Elem, Elem) bool) {
+       Sort(sliceFn[Elem]{s, f})
+}
index 95b9e918917cd50685cb27e3ac03dc9ca89e4877..cc795532b0c5bdea1fc42f17f4aadf48ec169dca 100644 (file)
@@ -319,8 +319,12 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
        }
 }
 
-func (p *printer) parameters(fields *ast.FieldList) {
-       p.print(fields.Opening, token.LPAREN)
+func (p *printer) parameters(fields *ast.FieldList, isTypeParam bool) {
+       openTok, closeTok := token.LPAREN, token.RPAREN
+       if isTypeParam {
+               openTok, closeTok = token.LBRACK, token.RBRACK
+       }
+       p.print(fields.Opening, openTok)
        if len(fields.List) > 0 {
                prevLine := p.lineFor(fields.Opening)
                ws := indent
@@ -328,13 +332,8 @@ func (p *printer) parameters(fields *ast.FieldList) {
                        // determine par begin and end line (may be different
                        // if there are multiple parameter names for this par
                        // or the type is on a separate line)
-                       var parLineBeg int
-                       if len(par.Names) > 0 {
-                               parLineBeg = p.lineFor(par.Names[0].Pos())
-                       } else {
-                               parLineBeg = p.lineFor(par.Type.Pos())
-                       }
-                       var parLineEnd = p.lineFor(par.Type.End())
+                       parLineBeg := p.lineFor(par.Pos())
+                       parLineEnd := p.lineFor(par.End())
                        // separating "," if needed
                        needsLinebreak := 0 < prevLine && prevLine < parLineBeg
                        if i > 0 {
@@ -379,25 +378,29 @@ func (p *printer) parameters(fields *ast.FieldList) {
                        p.print(unindent)
                }
        }
-       p.print(fields.Closing, token.RPAREN)
+       p.print(fields.Closing, closeTok)
 }
 
-func (p *printer) signature(params, result *ast.FieldList) {
-       if params != nil {
-               p.parameters(params)
+func (p *printer) signature(sig *ast.FuncType) {
+       if sig.TParams != nil {
+               p.parameters(sig.TParams, true)
+       }
+       if sig.Params != nil {
+               p.parameters(sig.Params, false)
        } else {
                p.print(token.LPAREN, token.RPAREN)
        }
-       n := result.NumFields()
+       res := sig.Results
+       n := res.NumFields()
        if n > 0 {
-               // result != nil
+               // res != nil
                p.print(blank)
-               if n == 1 && result.List[0].Names == nil {
-                       // single anonymous result; no ()'s
-                       p.expr(stripParensAlways(result.List[0].Type))
+               if n == 1 && res.List[0].Names == nil {
+                       // single anonymous res; no ()'s
+                       p.expr(stripParensAlways(res.List[0].Type))
                        return
                }
-               p.parameters(result)
+               p.parameters(res, false)
        }
 }
 
@@ -467,10 +470,18 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
                                }
                                p.expr(f.Type)
                        } else { // interface
-                               if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
-                                       // method
-                                       p.expr(f.Names[0])
-                                       p.signature(ftyp.Params, ftyp.Results)
+                               if len(f.Names) > 0 {
+                                       // type list type or method
+                                       name := f.Names[0] // "type" or method name
+                                       p.expr(name)
+                                       if name.Name == "type" {
+                                               // type list type
+                                               p.print(blank)
+                                               p.expr(f.Type)
+                                       } else {
+                                               // method
+                                               p.signature(f.Type.(*ast.FuncType)) // don't print "func"
+                                       }
                                } else {
                                        // embedded interface
                                        p.expr(f.Type)
@@ -538,19 +549,47 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
        } else { // interface
 
                var line int
+               var prev *ast.Ident // previous "type" identifier
                for i, f := range list {
+                       var name *ast.Ident // first name, or nil
+                       if len(f.Names) > 0 {
+                               name = f.Names[0]
+                       }
                        if i > 0 {
-                               p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
+                               // don't do a line break (min == 0) if we are printing a list of types
+                               // TODO(gri) this doesn't work quite right if the list of types is
+                               //           spread across multiple lines
+                               min := 1
+                               if prev != nil && name == prev {
+                                       min = 0
+                               }
+                               p.linebreak(p.lineFor(f.Pos()), min, ignore, p.linesFrom(line) > 0)
                        }
                        p.setComment(f.Doc)
                        p.recordLine(&line)
-                       if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
-                               // method
-                               p.expr(f.Names[0])
-                               p.signature(ftyp.Params, ftyp.Results)
+                       if name != nil {
+                               // type list type or method
+                               if name.Name == "type" {
+                                       // type list type
+                                       if name == prev {
+                                               // type is part of a list of types
+                                               p.print(token.COMMA, blank)
+                                       } else {
+                                               // type starts a new list of types
+                                               p.print(name, blank)
+                                       }
+                                       p.expr(f.Type)
+                                       prev = name
+                               } else {
+                                       // method
+                                       p.expr(name)
+                                       p.signature(f.Type.(*ast.FuncType)) // don't print "func"
+                                       prev = nil
+                               }
                        } else {
                                // embedded interface
                                p.expr(f.Type)
+                               prev = nil
                        }
                        p.setComment(f.Comment)
                }
@@ -800,7 +839,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
                p.print(x.Type.Pos(), token.FUNC)
                // See the comment in funcDecl about how the header size is computed.
                startCol := p.out.Column - len("func")
-               p.signature(x.Type.Params, x.Type.Results)
+               p.signature(x.Type)
                p.funcBody(p.distanceFrom(x.Type.Pos(), startCol), blank, x.Body)
 
        case *ast.ParenExpr:
@@ -880,25 +919,32 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
                        depth++
                }
                var wasIndented bool
-               if _, ok := x.Fun.(*ast.FuncType); ok {
-                       // conversions to literal function types require parentheses around the type
-                       p.print(token.LPAREN)
+               if x.Brackets {
                        wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
-                       p.print(token.RPAREN)
+                       p.print(x.Lparen, token.LBRACK)
+                       p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
+                       p.print(x.Rparen, token.RBRACK)
                } else {
-                       wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
-               }
-               p.print(x.Lparen, token.LPAREN)
-               if x.Ellipsis.IsValid() {
-                       p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis, false)
-                       p.print(x.Ellipsis, token.ELLIPSIS)
-                       if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) {
-                               p.print(token.COMMA, formfeed)
+                       if _, ok := x.Fun.(*ast.FuncType); ok {
+                               // conversions to literal function types require parentheses around the type
+                               p.print(token.LPAREN)
+                               wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
+                               p.print(token.RPAREN)
+                       } else {
+                               wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
                        }
-               } else {
-                       p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
+                       p.print(x.Lparen, token.LPAREN)
+                       if x.Ellipsis.IsValid() {
+                               p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis, false)
+                               p.print(x.Ellipsis, token.ELLIPSIS)
+                               if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) {
+                                       p.print(token.COMMA, formfeed)
+                               }
+                       } else {
+                               p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
+                       }
+                       p.print(x.Rparen, token.RPAREN)
                }
-               p.print(x.Rparen, token.RPAREN)
                if wasIndented {
                        p.print(unindent)
                }
@@ -945,7 +991,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
 
        case *ast.FuncType:
                p.print(token.FUNC)
-               p.signature(x.Params, x.Results)
+               p.signature(x)
 
        case *ast.InterfaceType:
                p.print(token.INTERFACE)
@@ -1585,6 +1631,9 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
        case *ast.TypeSpec:
                p.setComment(s.Doc)
                p.expr(s.Name)
+               if s.TParams != nil {
+                       p.parameters(s.TParams, true)
+               }
                if n == 1 {
                        p.print(blank)
                } else {
@@ -1773,11 +1822,11 @@ func (p *printer) funcDecl(d *ast.FuncDecl) {
        // FUNC is emitted).
        startCol := p.out.Column - len("func ")
        if d.Recv != nil {
-               p.parameters(d.Recv) // method: print receiver
+               p.parameters(d.Recv, false) // method: print receiver
                p.print(blank)
        }
        p.expr(d.Name)
-       p.signature(d.Type.Params, d.Type.Results)
+       p.signature(d.Type)
        p.funcBody(p.distanceFrom(d.Pos(), startCol), vtab, d.Body)
 }
 
index 45e501115ac6f98d95b1951fbbe97162760a7e8e..b15dcbf0002ccbfb9ef04be980a192df98fb72ac 100644 (file)
@@ -42,7 +42,7 @@ const (
 // if any.
 func format(src []byte, mode checkMode) ([]byte, error) {
        // parse src
-       f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
+       f, err := parser.ParseFile(fset, "", src, parser.ParseComments|parser.ParseTypeParams)
        if err != nil {
                return nil, fmt.Errorf("parse: %s\n%s", err, src)
        }
@@ -70,7 +70,7 @@ func format(src []byte, mode checkMode) ([]byte, error) {
 
        // make sure formatted output is syntactically correct
        res := buf.Bytes()
-       if _, err := parser.ParseFile(fset, "", res, 0); err != nil {
+       if _, err := parser.ParseFile(fset, "", res, parser.ParseTypeParams); err != nil {
                return nil, fmt.Errorf("re-parse: %s\n%s", err, buf.Bytes())
        }
 
@@ -206,6 +206,7 @@ var data = []entry{
        {"complit.input", "complit.x", export},
        {"go2numbers.input", "go2numbers.golden", idempotent},
        {"go2numbers.input", "go2numbers.norm", normNumber | idempotent},
+       {"generics.input", "generics.golden", idempotent},
 }
 
 func TestFiles(t *testing.T) {
index fe0f7838de50617b2ead0e15a3d65d53c736454f..74ffce7d73f867aa3392c47e7a28b1f552d32de7 100644 (file)
@@ -942,6 +942,13 @@ type _ interface {
                x ...int)
 }
 
+// properly format one-line type lists
+type _ interface{ type a }
+
+type _ interface {
+       type a, b, c
+}
+
 // omit superfluous parentheses in parameter lists
 func _(int)
 func _(int)
@@ -992,6 +999,10 @@ func _(struct {
        y       int
 })     // no extra comma between } and )
 
+// type parameters
+func _[A, B any](a A, b B) int {}
+func _[T any](x, y T) T
+
 // alias declarations
 
 type c0 struct{}
index a858051ef01a650d69a9d4a4039d53e601513cac..ab2022142a6d48bbeb50d6aa9af5bcb0dbe446fd 100644 (file)
@@ -955,6 +955,11 @@ r string,
                x ...int)
 }
 
+// properly format one-line type lists
+type _ interface { type a }
+
+type _ interface { type a,b,c }
+
 // omit superfluous parentheses in parameter lists
 func _((int))
 func _((((((int))))))
@@ -1005,6 +1010,10 @@ func _(struct {
        y int
 }) // no extra comma between } and )
 
+// type parameters
+func _[A, B any](a A, b B) int {}
+func _[T any](x, y T) T
+
 // alias declarations
 
 type c0 struct{}
@@ -1018,4 +1027,4 @@ type (
        c = foo
        d = interface{}
        ddd = p.Foo
-)
\ No newline at end of file
+)
diff --git a/src/go/printer/testdata/generics.golden b/src/go/printer/testdata/generics.golden
new file mode 100644 (file)
index 0000000..88c4616
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2020 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 generics
+
+type T[P any] struct{}
+type T[P1, P2, P3 any] struct{}
+
+type T[P C] struct{}
+type T[P1, P2, P3 C] struct{}
+
+type T[P C[P]] struct{}
+type T[P1, P2, P3 C[P1, P2, P3]] struct{}
+
+func f[P any](x P)
+func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
+
+func f[P interface{}](x P)
+func f[P1, P2, P3 interface {
+       m1(P1)
+       type P2, P3
+}](x1 P1, x2 P2, x3 P3) struct{}
+func f[P any](T1[P], T2[P]) T3[P]
+
+func (x T[P]) m()
+func (T[P]) m(x T[P]) P
+
+func _() {
+       type _ []T[P]
+       var _ []T[P]
+       _ = []T[P]{}
+}
diff --git a/src/go/printer/testdata/generics.input b/src/go/printer/testdata/generics.input
new file mode 100644 (file)
index 0000000..5fdf8cd
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2020 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 generics
+
+type T[P any] struct{}
+type T[P1, P2, P3 any] struct{}
+
+type T[P C] struct{}
+type T[P1, P2, P3 C] struct{}
+
+type T[P C[P]] struct{}
+type T[P1, P2, P3 C[P1, P2, P3]] struct{}
+
+func f[P any](x P)
+func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
+
+func f[P interface{}](x P)
+func f[P1, P2, P3 interface{ m1(P1); type P2, P3 }](x1 P1, x2 P2, x3 P3) struct{}
+func f[P any](T1[P], T2[P]) T3[P]
+
+func (x T[P]) m()
+func ((T[P])) m(x T[P]) P
+
+func _() {
+       type _ []T[P]
+       var _ []T[P]
+       _ = []T[P]{}
+}
index d6259598172035fdcbc966fdfc0725c2e35f0810..ec12fcf3804c3e898223635030d30551d16e3c58 100644 (file)
@@ -177,6 +177,12 @@ type Info struct {
        // qualified identifiers are collected in the Uses map.
        Types map[ast.Expr]TypeAndValue
 
+       // Inferred maps calls of parameterized functions that use
+       // type inference to the inferred type arguments and signature
+       // of the function called. The recorded "call" expression may be
+       // an *ast.CallExpr (as in f(x)), or an *ast.IndexExpr (s in f[T]).
+       Inferred map[ast.Expr]Inferred
+
        // Defs maps identifiers to the objects they define (including
        // package names, dots "." of dot-imports, and blank "_" identifiers).
        // For identifiers that do not denote objects (e.g., the package name
@@ -333,6 +339,13 @@ func (tv TypeAndValue) HasOk() bool {
        return tv.mode == commaok || tv.mode == mapindex
 }
 
+// Inferred reports the inferred type arguments and signature
+// for a parameterized function call that uses type inference.
+type Inferred struct {
+       Targs []Type
+       Sig   *Signature
+}
+
 // An Initializer describes a package-level variable, or a list of variables in case
 // of a multi-valued initialization expression, and the corresponding initialization
 // expression.
index 280792e838ef24bb62849c1b93904dc436770aba..d1672837b8d9d9b678edf595662eb407bd707070 100644 (file)
@@ -19,18 +19,18 @@ const (
        trace = false // turn on for detailed type resolution traces
 )
 
-// If Strict is set, the type-checker enforces additional
+// If forceStrict is set, the type-checker enforces additional
 // rules not specified by the Go 1 spec, but which will
 // catch guaranteed run-time errors if the respective
 // code is executed. In other words, programs passing in
-// Strict mode are Go 1 compliant, but not all Go 1 programs
-// will pass in Strict mode. The additional rules are:
+// strict mode are Go 1 compliant, but not all Go 1 programs
+// will pass in strict mode. The additional rules are:
 //
 // - A type assertion x.(T) where T is an interface type
 //   is invalid if any (statically known) method that exists
 //   for both x and T have different signatures.
 //
-const strict = false
+const forceStrict = false
 
 // exprInfo stores information about an untyped expression.
 type exprInfo struct {
@@ -78,9 +78,11 @@ type Checker struct {
        fset *token.FileSet
        pkg  *Package
        *Info
+       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
        posMap map[*Interface][]token.Pos // maps interface types to lists of embedded interface positions
+       typMap map[string]*Named          // maps an instantiated named type hash to a *Named type
        pkgCnt map[string]int             // counts number of imported packages with a given name (for better error messages)
 
        // information collected during type-checking of a set of package files
@@ -190,9 +192,11 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
                fset:   fset,
                pkg:    pkg,
                Info:   info,
+               nextId: 1,
                objMap: make(map[Object]*declInfo),
                impMap: make(map[importKey]*Package),
                posMap: make(map[*Interface][]token.Pos),
+               typMap: make(map[string]*Named),
                pkgCnt: make(map[string]int),
        }
 }
@@ -275,6 +279,10 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
 
        check.recordUntyped()
 
+       if check.Info != nil {
+               sanitizeInfo(check.Info)
+       }
+
        check.pkg.complete = true
        return
 }
@@ -377,6 +385,14 @@ func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) {
        }
 }
 
+func (check *Checker) recordInferred(call ast.Expr, targs []Type, sig *Signature) {
+       assert(call != nil)
+       assert(sig != nil)
+       if m := check.Inferred; m != nil {
+               m[call] = Inferred{targs, sig}
+       }
+}
+
 func (check *Checker) recordDef(id *ast.Ident, obj Object) {
        assert(id != nil)
        if m := check.Defs; m != nil {
index 1f0bc358a26e9ace5e0c3dcf396eaaf6079e2646..a822e08b1e0627ebaa1ded6fefce467e0515cae9 100644 (file)
@@ -5,6 +5,7 @@
 package types
 
 import (
+       "fmt"
        "go/ast"
        "go/constant"
        "go/token"
@@ -52,7 +53,10 @@ func pathString(path []Object) string {
 // objDecl type-checks the declaration of obj in its respective (file) context.
 // For the meaning of def, see Checker.definedType, in typexpr.go.
 func (check *Checker) objDecl(obj Object, def *Named) {
-       if trace {
+       if trace && obj.Type() == nil {
+               if check.indent == 0 {
+                       fmt.Println() // empty line between top-level objects for readability
+               }
                check.trace(obj.Pos(), "-- checking %s (%s, objPath = %s)", obj, obj.color(), pathString(check.objPath))
                check.indent++
                defer func() {
@@ -183,13 +187,14 @@ func (check *Checker) objDecl(obj Object, def *Named) {
        switch obj := obj.(type) {
        case *Const:
                check.decl = d // new package-level const decl
-               check.constDecl(obj, d.typ, d.init, d.inherited)
+               check.constDecl(obj, d.vtyp, d.init, d.inherited)
        case *Var:
                check.decl = d // new package-level var decl
-               check.varDecl(obj, d.lhs, d.typ, d.init)
+               check.varDecl(obj, d.lhs, d.vtyp, d.init)
        case *TypeName:
                // invalid recursive types are detected via path
-               check.typeDecl(obj, d.typ, def, d.alias)
+               check.typeDecl(obj, d.tdecl, def)
+               check.collectMethods(obj) // methods can only be added to top-level types
        case *Func:
                // functions may be recursive - no need to track dependencies
                check.funcDecl(obj, d)
@@ -234,7 +239,7 @@ func (check *Checker) cycle(obj Object) (isCycle bool) {
                        // this information explicitly in the object.
                        var alias bool
                        if d := check.objMap[obj]; d != nil {
-                               alias = d.alias // package-level object
+                               alias = d.tdecl.Assign.IsValid() // package-level object
                        } else {
                                alias = obj.IsAlias() // function local object
                        }
@@ -318,7 +323,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
                }
 
                // don't report a 2nd error if we already know the type is invalid
-               // (e.g., if a cycle was detected earlier, via Checker.underlying).
+               // (e.g., if a cycle was detected earlier, via under).
                if t.underlying == Typ[Invalid] {
                        t.info = invalid
                        return invalid
@@ -344,6 +349,9 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
                        panic("internal error: cycle start not found")
                }
                return t.info
+
+       case *instance:
+               return check.validType(t.expand(), path)
        }
 
        return valid
@@ -475,7 +483,7 @@ func (check *Checker) constDecl(obj *Const, typ, init ast.Expr, inherited bool)
                if !isConstType(t) {
                        // don't report an error if the type is an invalid C (defined) type
                        // (issue #22090)
-                       if t.Underlying() != Typ[Invalid] {
+                       if under(t) != Typ[Invalid] {
                                check.errorf(typ, _InvalidConstType, "invalid constant type %s", t)
                        }
                        obj.typ = Typ[Invalid]
@@ -506,7 +514,7 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
 
        // determine type, if any
        if typ != nil {
-               obj.typ = check.typ(typ)
+               obj.typ = check.varType(typ)
                // We cannot spread the type to all lhs variables if there
                // are more than one since that would mark them as checked
                // (see Checker.objDecl) and the assignment of init exprs,
@@ -561,36 +569,35 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
        check.initVars(lhs, []ast.Expr{init}, token.NoPos)
 }
 
-// underlying returns the underlying type of typ; possibly by following
-// forward chains of named types. Such chains only exist while named types
-// are incomplete. If an underlying type is found, resolve the chain by
-// setting the underlying type for each defined type in the chain before
-// returning it.
-//
-// If no underlying type is found, a cycle error is reported and Typ[Invalid]
-// is used as underlying type for each defined type in the chain and returned
-// as result.
-func (check *Checker) underlying(typ Type) Type {
-       // If typ is not a defined type, its underlying type is itself.
-       n0, _ := typ.(*Named)
-       if n0 == nil {
-               return typ // nothing to do
+// under returns the expanded underlying type of n0; possibly by following
+// forward chains of named types. If an underlying type is found, resolve
+// the chain by setting the underlying type for each defined type in the
+// chain before returning it. If no underlying type is found or a cycle
+// is detected, the result is Typ[Invalid]. If a cycle is detected and
+// n0.check != nil, the cycle is reported.
+func (n0 *Named) under() Type {
+       u := n0.underlying
+       if u == nil {
+               return Typ[Invalid]
        }
 
        // If the underlying type of a defined type is not a defined
        // type, then that is the desired underlying type.
-       typ = n0.underlying
-       n, _ := typ.(*Named)
+       n := asNamed(u)
        if n == nil {
-               return typ // common case
+               return u // common case
        }
 
        // Otherwise, follow the forward chain.
        seen := map[*Named]int{n0: 0}
        path := []Object{n0.obj}
        for {
-               typ = n.underlying
-               n1, _ := typ.(*Named)
+               u = n.underlying
+               if u == nil {
+                       u = Typ[Invalid]
+                       break
+               }
+               n1 := asNamed(u)
                if n1 == nil {
                        break // end of chain
                }
@@ -601,8 +608,12 @@ func (check *Checker) underlying(typ Type) Type {
 
                if i, ok := seen[n]; ok {
                        // cycle
-                       check.cycleError(path[i:])
-                       typ = Typ[Invalid]
+                       // TODO(rFindley) revert this to a method on Checker. Having a possibly
+                       // nil Checker on Named and TypeParam is too subtle.
+                       if n0.check != nil {
+                               n0.check.cycleError(path[i:])
+                       }
+                       u = Typ[Invalid]
                        break
                }
        }
@@ -611,13 +622,14 @@ func (check *Checker) underlying(typ Type) Type {
                // We should never have to update the underlying type of an imported type;
                // those underlying types should have been resolved during the import.
                // Also, doing so would lead to a race condition (was issue #31749).
-               if n.obj.pkg != check.pkg {
+               // Do this check always, not just in debug more (it's cheap).
+               if n0.check != nil && n.obj.pkg != n0.check.pkg {
                        panic("internal error: imported type with unresolved underlying type")
                }
-               n.underlying = typ
+               n.underlying = u
        }
 
-       return typ
+       return u
 }
 
 func (n *Named) setUnderlying(typ Type) {
@@ -626,26 +638,42 @@ func (n *Named) setUnderlying(typ Type) {
        }
 }
 
-func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, alias bool) {
+func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
        assert(obj.typ == nil)
 
        check.later(func() {
                check.validType(obj.typ, nil)
        })
 
+       alias := tdecl.Assign.IsValid()
+       if alias && tdecl.TParams != nil {
+               // The parser will ensure this but we may still get an invalid AST.
+               // Complain and continue as regular type definition.
+               check.error(atPos(tdecl.Assign), 0, "generic type cannot be alias")
+               alias = false
+       }
+
        if alias {
+               // type alias declaration
 
                obj.typ = Typ[Invalid]
-               obj.typ = check.typ(typ)
+               obj.typ = check.anyType(tdecl.Type)
 
        } else {
+               // defined type declaration
 
-               named := &Named{obj: obj}
+               named := &Named{check: check, obj: obj}
                def.setUnderlying(named)
                obj.typ = named // make sure recursive type declarations terminate
 
+               if tdecl.TParams != nil {
+                       check.openScope(tdecl, "type parameters")
+                       defer check.closeScope()
+                       named.tparams = check.collectTypeParams(tdecl.TParams)
+               }
+
                // determine underlying type of named
-               named.orig = check.definedType(typ, named)
+               named.orig = check.definedType(tdecl.Type, named)
 
                // The underlying type of named may be itself a named type that is
                // incomplete:
@@ -660,14 +688,85 @@ func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, alias bo
                // and which has as its underlying type the named type B.
                // Determine the (final, unnamed) underlying type by resolving
                // any forward chain.
-               named.underlying = check.underlying(named)
+               // TODO(gri) Investigate if we can just use named.origin here
+               //           and rely on lazy computation of the underlying type.
+               named.underlying = under(named)
+       }
+
+}
+
+func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeName) {
+       // Type parameter lists should not be empty. The parser will
+       // complain but we still may get an incorrect AST: ignore it.
+       if list.NumFields() == 0 {
+               return
+       }
+
+       // Declare type parameters up-front, with empty interface as type bound.
+       // The scope of type parameters starts at the beginning of the type parameter
+       // list (so we can have mutually recursive parameterized interfaces).
+       for _, f := range list.List {
+               tparams = check.declareTypeParams(tparams, f.Names)
+       }
+
+       setBoundAt := func(at int, bound Type) {
+               assert(IsInterface(bound))
+               tparams[at].typ.(*TypeParam).bound = bound
+       }
+
+       index := 0
+       var bound Type
+       for _, f := range list.List {
+               if f.Type == nil {
+                       goto next
+               }
+
+               // The predeclared identifier "any" is visible only as a constraint
+               // in a type parameter list. Look for it before general constraint
+               // resolution.
+               if tident, _ := f.Type.(*ast.Ident); tident != nil && tident.Name == "any" && check.lookup("any") == nil {
+                       bound = universeAny
+               } else {
+                       bound = check.typ(f.Type)
+               }
+
+               // type bound must be an interface
+               // TODO(gri) We should delay the interface check because
+               //           we may not have a complete interface yet:
+               //           type C(type T C) interface {}
+               //           (issue #39724).
+               if _, ok := under(bound).(*Interface); ok {
+                       // Otherwise, set the bound for each type parameter.
+                       for i := range f.Names {
+                               setBoundAt(index+i, bound)
+                       }
+               } else if bound != Typ[Invalid] {
+                       check.errorf(f.Type, 0, "%s is not an interface", bound)
+               }
 
+       next:
+               index += len(f.Names)
        }
 
-       check.addMethodDecls(obj)
+       return
 }
 
-func (check *Checker) addMethodDecls(obj *TypeName) {
+func (check *Checker) declareTypeParams(tparams []*TypeName, names []*ast.Ident) []*TypeName {
+       for _, name := range names {
+               tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil)
+               check.NewTypeParam(tpar, len(tparams), &emptyInterface) // assigns type to tpar as a side-effect
+               check.declare(check.scope, name, tpar, check.scope.pos) // TODO(gri) check scope position
+               tparams = append(tparams, tpar)
+       }
+
+       if trace && len(names) > 0 {
+               check.trace(names[0].Pos(), "type params = %v", tparams[len(tparams)-len(names):])
+       }
+
+       return tparams
+}
+
+func (check *Checker) collectMethods(obj *TypeName) {
        // get associated methods
        // (Checker.collectObjects only collects methods with non-blank names;
        // Checker.resolveBaseTypeName ensures that obj is not an alias name
@@ -677,14 +776,14 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
                return
        }
        delete(check.methods, obj)
-       assert(!check.objMap[obj].alias) // don't use TypeName.IsAlias (requires fully set up object)
+       assert(!check.objMap[obj].tdecl.Assign.IsValid()) // don't use TypeName.IsAlias (requires fully set up object)
 
        // use an objset to check for name conflicts
        var mset objset
 
        // spec: "If the base type is a struct type, the non-blank method
        // and field names must be distinct."
-       base, _ := obj.typ.(*Named) // shouldn't fail but be conservative
+       base := asNamed(obj.typ) // shouldn't fail but be conservative
        if base != nil {
                if t, _ := base.underlying.(*Struct); t != nil {
                        for _, fld := range t.fields {
@@ -735,12 +834,18 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
 
        sig := new(Signature)
        obj.typ = sig // guard against cycles
+
+       // Avoid cycle error when referring to method while type-checking the signature.
+       // This avoids a nuisance in the best case (non-parameterized receiver type) and
+       // since the method is not a type, we get an error. If we have a parameterized
+       // receiver type, instantiating the receiver type leads to the instantiation of
+       // its methods, and we don't want a cycle error in that case.
+       // TODO(gri) review if this is correct and/or whether we still need this?
+       saved := obj.color_
+       obj.color_ = black
        fdecl := decl.fdecl
        check.funcType(sig, fdecl.Recv, fdecl.Type)
-       if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
-               check.errorf(fdecl, _InvalidInitSig, "func init must have no arguments and no return values")
-               // ok to continue
-       }
+       obj.color_ = saved
 
        // function body must be type-checked after global declarations
        // (functions implemented elsewhere have no body)
@@ -846,7 +951,7 @@ func (check *Checker) declStmt(d ast.Decl) {
                        check.declare(check.scope, d.spec.Name, obj, scopePos)
                        // mark and unmark type before calling typeDecl; its type is still nil (see Checker.objDecl)
                        obj.setColor(grey + color(check.push(obj)))
-                       check.typeDecl(obj, d.spec.Type, nil, d.spec.Assign.IsValid())
+                       check.typeDecl(obj, d.spec, nil)
                        check.pop().setColor(black)
                default:
                        check.invalidAST(d.node(), "unknown ast.Decl node %T", d.node())
index eb2056125a7b71aecf3efb362cd98ec5146a09a1..c57edf8f0d37ae847aa1ce8aca03804c7ecd0301 100644 (file)
@@ -58,11 +58,16 @@ the type (and constant value, if any) is recorded via Info.Types, if present.
 
 type opPredicates map[token.Token]func(Type) bool
 
-var unaryOpPredicates = opPredicates{
-       token.ADD: isNumeric,
-       token.SUB: isNumeric,
-       token.XOR: isInteger,
-       token.NOT: isBoolean,
+var unaryOpPredicates opPredicates
+
+func init() {
+       // Setting unaryOpPredicates in init avoids declaration cycles.
+       unaryOpPredicates = opPredicates{
+               token.ADD: isNumeric,
+               token.SUB: isNumeric,
+               token.XOR: isInteger,
+               token.NOT: isBoolean,
+       }
 }
 
 func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
@@ -591,7 +596,7 @@ func (check *Checker) implicitType(x *operand, target Type) Type {
                        return Typ[UntypedNil]
                }
                // cannot assign untyped values to non-empty interfaces
-               check.completeInterface(t)
+               check.completeInterface(token.NoPos, t)
                if !t.Empty() {
                        return nil
                }
@@ -785,20 +790,25 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
        x.mode = value
 }
 
-var binaryOpPredicates = opPredicates{
-       token.ADD: func(typ Type) bool { return isNumeric(typ) || isString(typ) },
-       token.SUB: isNumeric,
-       token.MUL: isNumeric,
-       token.QUO: isNumeric,
-       token.REM: isInteger,
+var binaryOpPredicates opPredicates
+
+func init() {
+       // Setting binaryOpPredicates in init avoids declaration cycles.
+       binaryOpPredicates = opPredicates{
+               token.ADD: isNumericOrString,
+               token.SUB: isNumeric,
+               token.MUL: isNumeric,
+               token.QUO: isNumeric,
+               token.REM: isInteger,
 
-       token.AND:     isInteger,
-       token.OR:      isInteger,
-       token.XOR:     isInteger,
-       token.AND_NOT: isInteger,
+               token.AND:     isInteger,
+               token.OR:      isInteger,
+               token.XOR:     isInteger,
+               token.AND_NOT: isInteger,
 
-       token.LAND: isBoolean,
-       token.LOR:  isBoolean,
+               token.LAND: isBoolean,
+               token.LOR:  isBoolean,
+       }
 }
 
 // The binary expression e may be nil. It's passed in for better error messages only.
index 28d605f5ee8410a08fff044bfa5be2f571a2922b..0d9ae58dfc5a4d396338ccc368680982661d3640 100644 (file)
@@ -8,6 +8,7 @@ package types
 
 import (
        "bytes"
+       "fmt"
        "go/ast"
 )
 
@@ -31,7 +32,7 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
 
        switch x := x.(type) {
        default:
-               buf.WriteString("(bad expr)") // nil, ast.BadExpr, ast.KeyValueExpr
+               buf.WriteString(fmt.Sprintf("(ast: %T)", x)) // nil, ast.BadExpr, ast.KeyValueExpr
 
        case *ast.Ident:
                buf.WriteString(x.Name)
@@ -97,17 +98,16 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
 
        case *ast.CallExpr:
                WriteExpr(buf, x.Fun)
-               buf.WriteByte('(')
-               for i, arg := range x.Args {
-                       if i > 0 {
-                               buf.WriteString(", ")
-                       }
-                       WriteExpr(buf, arg)
+               var l, r byte = '(', ')'
+               if x.Brackets {
+                       l, r = '[', ']'
                }
+               buf.WriteByte(l)
+               writeExprList(buf, x.Args)
                if x.Ellipsis.IsValid() {
                        buf.WriteString("...")
                }
-               buf.WriteByte(')')
+               buf.WriteByte(r)
 
        case *ast.StarExpr:
                buf.WriteByte('*')
@@ -134,7 +134,7 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
 
        case *ast.StructType:
                buf.WriteString("struct{")
-               writeFieldList(buf, x.Fields, "; ", false)
+               writeFieldList(buf, x.Fields.List, "; ", false)
                buf.WriteByte('}')
 
        case *ast.FuncType:
@@ -142,8 +142,29 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
                writeSigExpr(buf, x)
 
        case *ast.InterfaceType:
+               // separate type list types from method list
+               // TODO(gri) we can get rid of this extra code if writeExprList does the separation
+               var types []ast.Expr
+               var methods []*ast.Field
+               for _, f := range x.Methods.List {
+                       if len(f.Names) > 1 && f.Names[0].Name == "type" {
+                               // type list type
+                               types = append(types, f.Type)
+                       } else {
+                               // method or embedded interface
+                               methods = append(methods, f)
+                       }
+               }
+
                buf.WriteString("interface{")
-               writeFieldList(buf, x.Methods, "; ", true)
+               writeFieldList(buf, methods, "; ", true)
+               if len(types) > 0 {
+                       if len(methods) > 0 {
+                               buf.WriteString("; ")
+                       }
+                       buf.WriteString("type ")
+                       writeExprList(buf, types)
+               }
                buf.WriteByte('}')
 
        case *ast.MapType:
@@ -169,7 +190,7 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
 
 func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) {
        buf.WriteByte('(')
-       writeFieldList(buf, sig.Params, ", ", false)
+       writeFieldList(buf, sig.Params.List, ", ", false)
        buf.WriteByte(')')
 
        res := sig.Results
@@ -188,23 +209,18 @@ func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) {
 
        // multiple or named result(s)
        buf.WriteByte('(')
-       writeFieldList(buf, res, ", ", false)
+       writeFieldList(buf, res.List, ", ", false)
        buf.WriteByte(')')
 }
 
-func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface bool) {
-       for i, f := range fields.List {
+func writeFieldList(buf *bytes.Buffer, list []*ast.Field, sep string, iface bool) {
+       for i, f := range list {
                if i > 0 {
                        buf.WriteString(sep)
                }
 
                // field list names
-               for i, name := range f.Names {
-                       if i > 0 {
-                               buf.WriteString(", ")
-                       }
-                       buf.WriteString(name.Name)
-               }
+               writeIdentList(buf, f.Names)
 
                // types of interface methods consist of signatures only
                if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface {
@@ -222,3 +238,21 @@ func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface
                // ignore tag
        }
 }
+
+func writeIdentList(buf *bytes.Buffer, list []*ast.Ident) {
+       for i, x := range list {
+               if i > 0 {
+                       buf.WriteString(", ")
+               }
+               buf.WriteString(x.Name)
+       }
+}
+
+func writeExprList(buf *bytes.Buffer, list []ast.Expr) {
+       for i, x := range list {
+               if i > 0 {
+                       buf.WriteString(", ")
+               }
+               WriteExpr(buf, x)
+       }
+}
diff --git a/src/go/types/infer.go b/src/go/types/infer.go
new file mode 100644 (file)
index 0000000..c0b1a4b
--- /dev/null
@@ -0,0 +1,359 @@
+// Copyright 2018 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.
+
+// This file implements type parameter inference given
+// a list of concrete arguments and a parameter list.
+
+package types
+
+import (
+       "go/token"
+       "strings"
+)
+
+// infer returns the list of actual type arguments for the given list of type parameters tparams
+// by inferring them from the actual arguments args for the parameters params. If type inference
+// is impossible because unification fails, an error is reported and the resulting types list is
+// nil, and index is 0. Otherwise, types is the list of inferred type arguments, and index is
+// the index of the first type argument in that list that couldn't be inferred (and thus is nil).
+// If all type arguments were inferred successfully, index is < 0.
+func (check *Checker) infer(tparams []*TypeName, params *Tuple, args []*operand) (types []Type, index int) {
+       assert(params.Len() == len(args))
+
+       u := newUnifier(check, false)
+       u.x.init(tparams)
+
+       errorf := func(kind string, tpar, targ Type, arg *operand) {
+               // provide a better error message if we can
+               targs, failed := u.x.types()
+               if failed == 0 {
+                       // The first type parameter couldn't be inferred.
+                       // If none of them could be inferred, don't try
+                       // to provide the inferred type in the error msg.
+                       allFailed := true
+                       for _, targ := range targs {
+                               if targ != nil {
+                                       allFailed = false
+                                       break
+                               }
+                       }
+                       if allFailed {
+                               check.errorf(arg, 0, "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeNamesString(tparams))
+                               return
+                       }
+               }
+               smap := makeSubstMap(tparams, targs)
+               // TODO(rFindley): pass a positioner here, rather than arg.Pos().
+               inferred := check.subst(arg.Pos(), tpar, smap)
+               if inferred != tpar {
+                       check.errorf(arg, 0, "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar)
+               } else {
+                       check.errorf(arg, 0, "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
+               }
+       }
+
+       // Terminology: generic parameter = function parameter with a type-parameterized type
+
+       // 1st pass: Unify parameter and argument types for generic parameters with typed arguments
+       //           and collect the indices of generic parameters with untyped arguments.
+       var indices []int
+       for i, arg := range args {
+               par := params.At(i)
+               // If we permit bidirectional unification, this conditional code needs to be
+               // executed even if par.typ is not parameterized since the argument may be a
+               // generic function (for which we want to infer // its type arguments).
+               if isParameterized(tparams, par.typ) {
+                       if arg.mode == invalid {
+                               // An error was reported earlier. Ignore this targ
+                               // and continue, we may still be able to infer all
+                               // targs resulting in fewer follon-on errors.
+                               continue
+                       }
+                       if targ := arg.typ; isTyped(targ) {
+                               // If we permit bidirectional unification, and targ is
+                               // a generic function, we need to initialize u.y with
+                               // the respective type parameters of targ.
+                               if !u.unify(par.typ, targ) {
+                                       errorf("type", par.typ, targ, arg)
+                                       return nil, 0
+                               }
+                       } else {
+                               indices = append(indices, i)
+                       }
+               }
+       }
+
+       // Some generic parameters with untyped arguments may have been given a type
+       // indirectly through another generic parameter with a typed argument; we can
+       // ignore those now. (This only means that we know the types for those generic
+       // parameters; it doesn't mean untyped arguments can be passed safely. We still
+       // need to verify that assignment of those arguments is valid when we check
+       // function parameter passing external to infer.)
+       j := 0
+       for _, i := range indices {
+               par := params.At(i)
+               // Since untyped types are all basic (i.e., non-composite) types, an
+               // untyped argument will never match a composite parameter type; the
+               // only parameter type it can possibly match against is a *TypeParam.
+               // Thus, only keep the indices of generic parameters that are not of
+               // composite types and which don't have a type inferred yet.
+               if tpar, _ := par.typ.(*TypeParam); tpar != nil && u.x.at(tpar.index) == nil {
+                       indices[j] = i
+                       j++
+               }
+       }
+       indices = indices[:j]
+
+       // 2nd pass: Unify parameter and default argument types for remaining generic parameters.
+       for _, i := range indices {
+               par := params.At(i)
+               arg := args[i]
+               targ := Default(arg.typ)
+               // The default type for an untyped nil is untyped nil. We must not
+               // infer an untyped nil type as type parameter type. Ignore untyped
+               // nil by making sure all default argument types are typed.
+               if isTyped(targ) && !u.unify(par.typ, targ) {
+                       errorf("default type", par.typ, targ, arg)
+                       return nil, 0
+               }
+       }
+
+       return u.x.types()
+}
+
+// typeNamesString produces a string containing all the
+// type names in list suitable for human consumption.
+func typeNamesString(list []*TypeName) string {
+       // common cases
+       n := len(list)
+       switch n {
+       case 0:
+               return ""
+       case 1:
+               return list[0].name
+       case 2:
+               return list[0].name + " and " + list[1].name
+       }
+
+       // general case (n > 2)
+       var b strings.Builder
+       for i, tname := range list[:n-1] {
+               if i > 0 {
+                       b.WriteString(", ")
+               }
+               b.WriteString(tname.name)
+       }
+       b.WriteString(", and ")
+       b.WriteString(list[n-1].name)
+       return b.String()
+}
+
+// IsParameterized reports whether typ contains any of the type parameters of tparams.
+func isParameterized(tparams []*TypeName, typ Type) bool {
+       w := tpWalker{
+               seen:    make(map[Type]bool),
+               tparams: tparams,
+       }
+       return w.isParameterized(typ)
+}
+
+type tpWalker struct {
+       seen    map[Type]bool
+       tparams []*TypeName
+}
+
+func (w *tpWalker) isParameterized(typ Type) (res bool) {
+       // detect cycles
+       if x, ok := w.seen[typ]; ok {
+               return x
+       }
+       w.seen[typ] = false
+       defer func() {
+               w.seen[typ] = res
+       }()
+
+       switch t := typ.(type) {
+       case nil, *Basic: // TODO(gri) should nil be handled here?
+               break
+
+       case *Array:
+               return w.isParameterized(t.elem)
+
+       case *Slice:
+               return w.isParameterized(t.elem)
+
+       case *Struct:
+               for _, fld := range t.fields {
+                       if w.isParameterized(fld.typ) {
+                               return true
+                       }
+               }
+
+       case *Pointer:
+               return w.isParameterized(t.base)
+
+       case *Tuple:
+               n := t.Len()
+               for i := 0; i < n; i++ {
+                       if w.isParameterized(t.At(i).typ) {
+                               return true
+                       }
+               }
+
+       case *Sum:
+               return w.isParameterizedList(t.types)
+
+       case *Signature:
+               // t.tparams may not be nil if we are looking at a signature
+               // of a generic function type (or an interface method) that is
+               // part of the type we're testing. We don't care about these type
+               // parameters.
+               // Similarly, the receiver of a method may declare (rather then
+               // use) type parameters, we don't care about those either.
+               // Thus, we only need to look at the input and result parameters.
+               return w.isParameterized(t.params) || w.isParameterized(t.results)
+
+       case *Interface:
+               if t.allMethods != nil {
+                       // TODO(rFindley) at some point we should enforce completeness here
+                       for _, m := range t.allMethods {
+                               if w.isParameterized(m.typ) {
+                                       return true
+                               }
+                       }
+                       return w.isParameterizedList(unpackType(t.allTypes))
+               }
+
+               return t.iterate(func(t *Interface) bool {
+                       for _, m := range t.methods {
+                               if w.isParameterized(m.typ) {
+                                       return true
+                               }
+                       }
+                       return w.isParameterizedList(unpackType(t.types))
+               }, nil)
+
+       case *Map:
+               return w.isParameterized(t.key) || w.isParameterized(t.elem)
+
+       case *Chan:
+               return w.isParameterized(t.elem)
+
+       case *Named:
+               return w.isParameterizedList(t.targs)
+
+       case *TypeParam:
+               // t must be one of w.tparams
+               return t.index < len(w.tparams) && w.tparams[t.index].typ == t
+
+       case *instance:
+               return w.isParameterizedList(t.targs)
+
+       default:
+               unreachable()
+       }
+
+       return false
+}
+
+func (w *tpWalker) isParameterizedList(list []Type) bool {
+       for _, t := range list {
+               if w.isParameterized(t) {
+                       return true
+               }
+       }
+       return false
+}
+
+// inferB returns the list of actual type arguments inferred from the type parameters'
+// bounds and an initial set of type arguments. If type inference is impossible because
+// unification fails, an error is reported, the resulting types list is nil, and index is 0.
+// Otherwise, types is the list of inferred type arguments, and index is the index of the
+// first type argument in that list that couldn't be inferred (and thus is nil). If all
+// type arguments where inferred successfully, index is < 0. The number of type arguments
+// provided may be less than the number of type parameters, but there must be at least one.
+func (check *Checker) inferB(tparams []*TypeName, targs []Type) (types []Type, index int) {
+       assert(len(tparams) >= len(targs) && len(targs) > 0)
+
+       // Setup bidirectional unification between those structural bounds
+       // and the corresponding type arguments (which may be nil!).
+       u := newUnifier(check, false)
+       u.x.init(tparams)
+       u.y = u.x // type parameters between LHS and RHS of unification are identical
+
+       // Set the type arguments which we know already.
+       for i, targ := range targs {
+               if targ != nil {
+                       u.x.set(i, targ)
+               }
+       }
+
+       // Unify type parameters with their structural constraints, if any.
+       for _, tpar := range tparams {
+               typ := tpar.typ.(*TypeParam)
+               sbound := check.structuralType(typ.bound)
+               if sbound != nil {
+                       if !u.unify(typ, sbound) {
+                               check.errorf(tpar, 0, "%s does not match %s", tpar, sbound)
+                               return nil, 0
+                       }
+               }
+       }
+
+       // u.x.types() now contains the incoming type arguments plus any additional type
+       // arguments for which there were structural constraints. The newly inferred non-
+       // nil entries may still contain references to other type parameters. For instance,
+       // for [A any, B interface{type []C}, C interface{type *A}], if A == int
+       // was given, unification produced the type list [int, []C, *A]. We eliminate the
+       // remaining type parameters by substituting the type parameters in this type list
+       // until nothing changes anymore.
+       types, index = u.x.types()
+       if debug {
+               for i, targ := range targs {
+                       assert(targ == nil || types[i] == targ)
+               }
+       }
+
+       // dirty tracks the indices of all types that may still contain type parameters.
+       // We know that nil type entries and entries corresponding to provided (non-nil)
+       // type arguments are clean, so exclude them from the start.
+       var dirty []int
+       for i, typ := range types {
+               if typ != nil && (i >= len(targs) || targs[i] == nil) {
+                       dirty = append(dirty, i)
+               }
+       }
+
+       for len(dirty) > 0 {
+               // TODO(gri) Instead of creating a new substMap for each iteration,
+               // provide an update operation for substMaps and only change when
+               // needed. Optimization.
+               smap := makeSubstMap(tparams, types)
+               n := 0
+               for _, index := range dirty {
+                       t0 := types[index]
+                       if t1 := check.subst(token.NoPos, t0, smap); t1 != t0 {
+                               types[index] = t1
+                               dirty[n] = index
+                               n++
+                       }
+               }
+               dirty = dirty[:n]
+       }
+
+       return
+}
+
+// structuralType returns the structural type of a constraint, if any.
+func (check *Checker) structuralType(constraint Type) Type {
+       if iface, _ := under(constraint).(*Interface); iface != nil {
+               check.completeInterface(token.NoPos, iface)
+               types := unpackType(iface.allTypes)
+               if len(types) == 1 {
+                       return types[0]
+               }
+               return nil
+       }
+       return constraint
+}
index 3c9ff182ec7c2446628ad857fa9264dbe2126115..f385ac993f7bd3a8467c9ee5525f03a900cd3edf 100644 (file)
@@ -6,6 +6,8 @@
 
 package types
 
+import "go/token"
+
 // LookupFieldOrMethod looks up a field or method with given package and name
 // in T and returns the corresponding *Var or *Func, an index sequence, and a
 // bool indicating if there were any pointer indirections on the path to the
@@ -53,7 +55,7 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package
        // Thus, if we have a named pointer type, proceed with the underlying
        // pointer type but discard the result if it is a method since we would
        // not have found it for T (see also issue 8590).
-       if t, _ := T.(*Named); t != nil {
+       if t := asNamed(T); t != nil {
                if p, _ := t.underlying.(*Pointer); p != nil {
                        obj, index, indirect = check.rawLookupFieldOrMethod(p, false, pkg, name)
                        if _, ok := obj.(*Func); ok {
@@ -83,7 +85,8 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
        typ, isPtr := deref(T)
 
        // *typ where typ is an interface has no methods.
-       if isPtr && IsInterface(typ) {
+       // Be cautious: typ may be nil (issue 39634, crash #3).
+       if typ == nil || isPtr && IsInterface(typ) {
                return
        }
 
@@ -104,12 +107,13 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
                var next []embeddedType // embedded types found at current depth
 
                // look for (pkg, name) in all types at current depth
+               var tpar *TypeParam // set if obj receiver is a type parameter
                for _, e := range current {
                        typ := e.typ
 
                        // If we have a named type, we may have associated methods.
                        // Look for those first.
-                       if named, _ := typ.(*Named); named != nil {
+                       if named := asNamed(typ); named != nil {
                                if seen[named] {
                                        // We have seen this type before, at a more shallow depth
                                        // (note that multiples of this type at the current depth
@@ -136,10 +140,15 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
                                        continue // we can't have a matching field or interface method
                                }
 
-                               // continue with underlying type
-                               typ = named.underlying
+                               // continue with underlying type, but only if it's not a type parameter
+                               // TODO(gri) is this what we want to do for type parameters? (spec question)
+                               typ = named.under()
+                               if asTypeParam(typ) != nil {
+                                       continue
+                               }
                        }
 
+                       tpar = nil
                        switch t := typ.(type) {
                        case *Struct:
                                // look for a matching field and collect embedded types
@@ -175,7 +184,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
                        case *Interface:
                                // look for a matching method
                                // TODO(gri) t.allMethods is sorted - use binary search
-                               check.completeInterface(t)
+                               check.completeInterface(token.NoPos, t)
                                if i, m := lookupMethod(t.allMethods, pkg, name); m != nil {
                                        assert(m.typ != nil)
                                        index = concat(e.index, i)
@@ -185,6 +194,20 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
                                        obj = m
                                        indirect = e.indirect
                                }
+
+                       case *TypeParam:
+                               // only consider explicit methods in the type parameter bound, not
+                               // methods that may be common to all types in the type list.
+                               if i, m := lookupMethod(t.Bound().allMethods, pkg, name); m != nil {
+                                       assert(m.typ != nil)
+                                       index = concat(e.index, i)
+                                       if obj != nil || e.multiples {
+                                               return nil, index, false // collision
+                                       }
+                                       tpar = t
+                                       obj = m
+                                       indirect = e.indirect
+                               }
                        }
                }
 
@@ -194,8 +217,12 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
                        //        contains m and the argument list can be assigned to the parameter
                        //        list of m. If x is addressable and &x's method set contains m, x.m()
                        //        is shorthand for (&x).m()".
-                       if f, _ := obj.(*Func); f != nil && ptrRecv(f) && !indirect && !addressable {
-                               return nil, nil, true // pointer/addressable receiver required
+                       if f, _ := obj.(*Func); f != nil {
+                               // determine if method has a pointer receiver
+                               hasPtrRecv := tpar == nil && ptrRecv(f)
+                               if hasPtrRecv && !indirect && !addressable {
+                                       return nil, nil, true // pointer/addressable receiver required
+                               }
                        }
                        return
                }
@@ -267,7 +294,8 @@ func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType b
        return m, typ != nil
 }
 
-// missingMethod is like MissingMethod but accepts a receiver.
+// missingMethod is like MissingMethod but accepts a *Checker as
+// receiver and an addressable flag.
 // The receiver may be nil if missingMethod is invoked through
 // an exported API call (such as MissingMethod), i.e., when all
 // methods have been type-checked.
@@ -276,32 +304,44 @@ func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType b
 // To improve error messages, also report the wrong signature
 // when the method exists on *V instead of V.
 func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, wrongType *Func) {
-       check.completeInterface(T)
+       check.completeInterface(token.NoPos, T)
 
        // fast path for common case
        if T.Empty() {
                return
        }
 
-       if ityp, _ := V.Underlying().(*Interface); ityp != nil {
-               check.completeInterface(ityp)
+       if ityp := asInterface(V); ityp != nil {
+               check.completeInterface(token.NoPos, ityp)
                // TODO(gri) allMethods is sorted - can do this more efficiently
                for _, m := range T.allMethods {
-                       _, obj := lookupMethod(ityp.allMethods, m.pkg, m.name)
-                       switch {
-                       case obj == nil:
-                               if static {
-                                       return m, nil
+                       _, f := lookupMethod(ityp.allMethods, m.pkg, m.name)
+
+                       if f == nil {
+                               // if m is the magic method == we're ok (interfaces are comparable)
+                               if m.name == "==" || !static {
+                                       continue
                                }
-                       case !check.identical(obj.Type(), m.typ):
-                               return m, obj
+                               return m, f
+                       }
+
+                       if !check.identical(f.Type(), m.Type()) {
+                               return m, f
                        }
+
+                       // TODO(rFindley) delete this note once the spec has stabilized to
+                       //                exclude method type parameters.
+                       // NOTE: if enabling method type parameters, we need to unify f.Type()
+                       // and m.Type() here to verify that their type parameters align (assuming
+                       // this behaves correctly with respect to type bounds).
                }
+
                return
        }
 
        // A concrete type implements T if it implements all methods of T.
        for _, m := range T.allMethods {
+               // TODO(gri) should this be calling lookupFieldOrMethod instead (and why not)?
                obj, _, _ := check.rawLookupFieldOrMethod(V, false, m.pkg, m.name)
 
                // Check if *V implements this method of T.
@@ -316,6 +356,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                // we must have a method (not a field of matching function type)
                f, _ := obj.(*Func)
                if f == nil {
+                       // if m is the magic method == and V is comparable, we're ok
+                       if m.name == "==" && Comparable(V) {
+                               continue
+                       }
                        return m, nil
                }
 
@@ -324,9 +368,16 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                        check.objDecl(f, nil)
                }
 
-               if !check.identical(f.typ, m.typ) {
+               if !check.identical(f.Type(), m.Type()) {
                        return m, f
                }
+
+               // TODO(rFindley) delete this note once the spec has stabilized to exclude
+               //                method type parameters.
+               // NOTE: if enabling method type parameters, one needs to subst any
+               // receiver type parameters for V here, and unify f.Type() with m.Type() to
+               // verify that their type parameters align (assuming this behaves correctly
+               // with respect to type bounds).
        }
 
        return
@@ -337,11 +388,13 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
 // method required by V and whether it is missing or just has the wrong type.
 // The receiver may be nil if assertableTo is invoked through an exported API call
 // (such as AssertableTo), i.e., when all methods have been type-checked.
+// If the global constant forceStrict is set, assertions that are known to fail
+// are not permitted.
 func (check *Checker) assertableTo(V *Interface, T Type) (method, wrongType *Func) {
        // no static check is required if T is an interface
        // spec: "If T is an interface type, x.(T) asserts that the
        //        dynamic type of x implements the interface T."
-       if _, ok := T.Underlying().(*Interface); ok && !strict {
+       if asInterface(T) != nil && !forceStrict {
                return
        }
        return check.missingMethod(T, V, false)
@@ -359,8 +412,8 @@ func deref(typ Type) (Type, bool) {
 // derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a
 // (named or unnamed) struct and returns its base. Otherwise it returns typ.
 func derefStructPtr(typ Type) Type {
-       if p, _ := typ.Underlying().(*Pointer); p != nil {
-               if _, ok := p.base.Underlying().(*Struct); ok {
+       if p := asPointer(typ); p != nil {
+               if asStruct(p.base) != nil {
                        return p.base
                }
        }
index c34d732b7ac36494427b329301397dbb7f848a2c..c44009f1a5e3a1ae2159cf54e34f9dd82297f3f6 100644 (file)
@@ -73,6 +73,9 @@ func NewMethodSet(T Type) *MethodSet {
        // WARNING: The code in this function is extremely subtle - do not modify casually!
        //          This function and lookupFieldOrMethod should be kept in sync.
 
+       // TODO(gri) This code is out-of-sync with the lookup code at this point.
+       //           Need to update.
+
        // method set up to the current depth, allocated lazily
        var base methodSet
 
@@ -108,7 +111,7 @@ func NewMethodSet(T Type) *MethodSet {
 
                        // If we have a named type, we may have associated methods.
                        // Look for those first.
-                       if named, _ := typ.(*Named); named != nil {
+                       if named := asNamed(typ); named != nil {
                                if seen[named] {
                                        // We have seen this type before, at a more shallow depth
                                        // (note that multiples of this type at the current depth
index 374b24d1acfa03e47da92ba7dd49f9e5297db13c..50346ec6919407e41e730b09c849a324938b18de 100644 (file)
@@ -36,6 +36,9 @@ type Object interface {
        // color returns the object's color.
        color() color
 
+       // setType sets the type of the object.
+       setType(Type)
+
        // setOrder sets the order number of the object. It must be > 0.
        setOrder(uint32)
 
@@ -149,6 +152,7 @@ func (obj *object) color() color        { return obj.color_ }
 func (obj *object) scopePos() token.Pos { return obj.scopePos_ }
 
 func (obj *object) setParent(parent *Scope)   { obj.parent = parent }
+func (obj *object) setType(typ Type)          { obj.typ = typ }
 func (obj *object) setOrder(order uint32)     { assert(order > 0); obj.order_ = order }
 func (obj *object) setColor(color color)      { assert(color != white); obj.color_ = color }
 func (obj *object) setScopePos(pos token.Pos) { obj.scopePos_ = pos }
@@ -299,7 +303,7 @@ type Func struct {
 // NewFunc returns a new function with the given signature, representing
 // the function's type.
 func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
-       // don't store a nil signature
+       // don't store a (typed) nil signature
        var typ Type
        if sig != nil {
                typ = sig
@@ -420,7 +424,7 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
                if tname.IsAlias() {
                        buf.WriteString(" =")
                } else {
-                       typ = typ.Underlying()
+                       typ = under(typ)
                }
        }
 
index 148edbfb767a47d642077d1dbe2c42ed692779f4..85e2b9a0cad48b9d0e8b7067423e42dca46a6b78 100644 (file)
@@ -6,75 +6,84 @@
 
 package types
 
-import "sort"
+import (
+       "go/token"
+       "sort"
+)
 
+// isNamed reports whether typ has a name.
+// isNamed may be called with types that are not fully set up.
 func isNamed(typ Type) bool {
-       if _, ok := typ.(*Basic); ok {
-               return ok
+       switch typ.(type) {
+       case *Basic, *Named, *TypeParam, *instance:
+               return true
        }
-       _, ok := typ.(*Named)
-       return ok
-}
-
-func isBoolean(typ Type) bool {
-       t, ok := typ.Underlying().(*Basic)
-       return ok && t.info&IsBoolean != 0
-}
-
-func isInteger(typ Type) bool {
-       t, ok := typ.Underlying().(*Basic)
-       return ok && t.info&IsInteger != 0
-}
-
-func isUnsigned(typ Type) bool {
-       t, ok := typ.Underlying().(*Basic)
-       return ok && t.info&IsUnsigned != 0
-}
-
-func isFloat(typ Type) bool {
-       t, ok := typ.Underlying().(*Basic)
-       return ok && t.info&IsFloat != 0
-}
-
-func isComplex(typ Type) bool {
-       t, ok := typ.Underlying().(*Basic)
-       return ok && t.info&IsComplex != 0
+       return false
 }
 
-func isNumeric(typ Type) bool {
-       t, ok := typ.Underlying().(*Basic)
-       return ok && t.info&IsNumeric != 0
+// isGeneric reports whether a type is a generic, uninstantiated type (generic
+// signatures are not included).
+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.tparams != nil && named.targs == nil
 }
 
-func isString(typ Type) bool {
-       t, ok := typ.Underlying().(*Basic)
-       return ok && t.info&IsString != 0
+func is(typ Type, what BasicInfo) bool {
+       switch t := optype(typ).(type) {
+       case *Basic:
+               return t.info&what != 0
+       case *Sum:
+               return t.is(func(typ Type) bool { return is(typ, what) })
+       }
+       return false
 }
 
+func isBoolean(typ Type) bool  { return is(typ, IsBoolean) }
+func isInteger(typ Type) bool  { return is(typ, IsInteger) }
+func isUnsigned(typ Type) bool { return is(typ, IsUnsigned) }
+func isFloat(typ Type) bool    { return is(typ, IsFloat) }
+func isComplex(typ Type) bool  { return is(typ, IsComplex) }
+func isNumeric(typ Type) bool  { return is(typ, IsNumeric) }
+func isString(typ Type) bool   { return is(typ, IsString) }
+
+// Note that if typ is a type parameter, isInteger(typ) || isFloat(typ) does not
+// produce the expected result because a type list that contains both an integer
+// and a floating-point type is neither (all) integers, nor (all) floats.
+// Use isIntegerOrFloat instead.
+func isIntegerOrFloat(typ Type) bool { return is(typ, IsInteger|IsFloat) }
+
+// isNumericOrString is the equivalent of isIntegerOrFloat for isNumeric(typ) || isString(typ).
+func isNumericOrString(typ Type) bool { return is(typ, IsNumeric|IsString) }
+
+// isTyped reports whether typ is typed; i.e., not an untyped
+// constant or boolean. isTyped may be called with types that
+// are not fully set up.
 func isTyped(typ Type) bool {
-       t, ok := typ.Underlying().(*Basic)
-       return !ok || t.info&IsUntyped == 0
+       // isTyped is called with types that are not fully
+       // set up. Must not call asBasic()!
+       // A *Named or *instance type is always typed, so
+       // we only need to check if we have a true *Basic
+       // type.
+       t, _ := typ.(*Basic)
+       return t == nil || t.info&IsUntyped == 0
 }
 
+// isUntyped(typ) is the same as !isTyped(typ).
 func isUntyped(typ Type) bool {
-       t, ok := typ.Underlying().(*Basic)
-       return ok && t.info&IsUntyped != 0
+       return !isTyped(typ)
 }
 
-func isOrdered(typ Type) bool {
-       t, ok := typ.Underlying().(*Basic)
-       return ok && t.info&IsOrdered != 0
-}
+func isOrdered(typ Type) bool { return is(typ, IsOrdered) }
 
 func isConstType(typ Type) bool {
-       t, ok := typ.Underlying().(*Basic)
-       return ok && t.info&IsConstType != 0
+       t := asBasic(typ)
+       return t != nil && t.info&IsConstType != 0
 }
 
 // IsInterface reports whether typ is an interface type.
 func IsInterface(typ Type) bool {
-       _, ok := typ.Underlying().(*Interface)
-       return ok
+       return asInterface(typ) != nil
 }
 
 // Comparable reports whether values of type T are comparable.
@@ -91,7 +100,19 @@ func comparable(T Type, seen map[Type]bool) bool {
        }
        seen[T] = true
 
-       switch t := T.Underlying().(type) {
+       // If T is a type parameter not constrained by any type
+       // list (i.e., it's underlying type is the top type),
+       // T is comparable if it has the == method. Otherwise,
+       // the underlying type "wins". For instance
+       //
+       //     interface{ comparable; type []byte }
+       //
+       // is not comparable because []byte is not comparable.
+       if t := asTypeParam(T); t != nil && optype(t) == theTop {
+               return t.Bound().IsComparable()
+       }
+
+       switch t := optype(T).(type) {
        case *Basic:
                // assume invalid types to be comparable
                // to avoid follow-up errors
@@ -107,17 +128,26 @@ func comparable(T Type, seen map[Type]bool) bool {
                return true
        case *Array:
                return comparable(t.elem, seen)
+       case *Sum:
+               pred := func(t Type) bool {
+                       return comparable(t, seen)
+               }
+               return t.is(pred)
+       case *TypeParam:
+               return t.Bound().IsComparable()
        }
        return false
 }
 
 // hasNil reports whether a type includes the nil value.
 func hasNil(typ Type) bool {
-       switch t := typ.Underlying().(type) {
+       switch t := optype(typ).(type) {
        case *Basic:
                return t.kind == UnsafePointer
        case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
                return true
+       case *Sum:
+               return t.is(hasNil)
        }
        return false
 }
@@ -144,7 +174,12 @@ func (p *ifacePair) identical(q *ifacePair) bool {
        return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
 }
 
+// For changes to this code the corresponding changes should be made to unifier.nify.
 func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
+       // types must be expanded for comparison
+       x = expandf(x)
+       y = expandf(y)
+
        if x == y {
                return true
        }
@@ -221,12 +256,38 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
                // and result values, corresponding parameter and result types are identical,
                // and either both functions are variadic or neither is. Parameter and result
                // names are not required to match.
+               // Generic functions must also have matching type parameter lists, but for the
+               // parameter names.
                if y, ok := y.(*Signature); ok {
                        return x.variadic == y.variadic &&
+                               check.identicalTParams(x.tparams, y.tparams, cmpTags, p) &&
                                check.identical0(x.params, y.params, cmpTags, p) &&
                                check.identical0(x.results, y.results, cmpTags, p)
                }
 
+       case *Sum:
+               // Two sum types are identical if they contain the same types.
+               // (Sum types always consist of at least two types. Also, the
+               // the set (list) of types in a sum type consists of unique
+               // types - each type appears exactly once. Thus, two sum types
+               // must contain the same number of types to have chance of
+               // being equal.
+               if y, ok := y.(*Sum); ok && len(x.types) == len(y.types) {
+                       // Every type in x.types must be in y.types.
+                       // Quadratic algorithm, but probably good enough for now.
+                       // TODO(gri) we need a fast quick type ID/hash for all types.
+               L:
+                       for _, x := range x.types {
+                               for _, y := range y.types {
+                                       if Identical(x, y) {
+                                               continue L // x is in y.types
+                                       }
+                               }
+                               return false // x is not in y.types
+                       }
+                       return true
+               }
+
        case *Interface:
                // Two interface types are identical if they have the same set of methods with
                // the same names and identical function types. Lower-case method names from
@@ -237,8 +298,8 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
                        // that case, interfaces are expected to be complete and lazy completion
                        // here is not needed.
                        if check != nil {
-                               check.completeInterface(x)
-                               check.completeInterface(y)
+                               check.completeInterface(token.NoPos, x)
+                               check.completeInterface(token.NoPos, y)
                        }
                        a := x.allMethods
                        b := y.allMethods
@@ -303,10 +364,25 @@ func (check *Checker) identical0(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 {
+                       // TODO(gri) Why is x == y not sufficient? And if it is,
+                       //           we can just return false here because x == y
+                       //           is caught in the very beginning of this function.
                        return x.obj == y.obj
                }
 
+       case *TypeParam:
+               // nothing to do (x and y being equal is caught in the very beginning of this function)
+
+       // case *instance:
+       //      unreachable since types are expanded
+
+       case *bottom, *top:
+               // Either both types are theBottom, or both are theTop in which
+               // case the initial x == y check will have caught them. Otherwise
+               // they are not identical.
+
        case nil:
+               // avoid a crash in case of nil type
 
        default:
                unreachable()
@@ -315,6 +391,19 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair) bool {
        return false
 }
 
+func (check *Checker) identicalTParams(x, y []*TypeName, cmpTags bool, p *ifacePair) bool {
+       if len(x) != len(y) {
+               return false
+       }
+       for i, x := range x {
+               y := y[i]
+               if !check.identical0(x.typ.(*TypeParam).bound, y.typ.(*TypeParam).bound, cmpTags, p) {
+                       return false
+               }
+       }
+       return true
+}
+
 // Default returns the default "typed" type for an "untyped" type;
 // it returns the incoming type for all other types. The default type
 // for untyped nil is untyped nil.
index b637f8b8cacf75793f564660081bc0c741daab1f..9cd13987beb3292996dc6d8c2fc4b18ebcc61bee 100644 (file)
@@ -19,11 +19,11 @@ import (
 type declInfo struct {
        file      *Scope        // scope of file containing this declaration
        lhs       []*Var        // lhs of n:1 variable declarations, or nil
-       typ       ast.Expr      // type, or nil
-       init      ast.Expr      // init/orig expression, or nil
+       vtyp      ast.Expr      // type, or nil (for const and var declarations only)
+       init      ast.Expr      // init/orig expression, or nil (for const and var declarations only)
        inherited bool          // if set, the init expression is inherited from a previous constant declaration
+       tdecl     *ast.TypeSpec // type declaration, or nil
        fdecl     *ast.FuncDecl // func declaration, or nil
-       alias     bool          // type alias declaration
 
        // The deps field tracks initialization expression dependencies.
        deps map[Object]bool // lazily initialized
@@ -216,7 +216,13 @@ func (check *Checker) collectObjects() {
                pkgImports[imp] = true
        }
 
-       var methods []*Func // list of methods with non-blank _ names
+       type methodInfo struct {
+               obj  *Func      // method
+               ptr  bool       // true if pointer receiver
+               recv *ast.Ident // receiver type name
+       }
+       var methods []methodInfo // collected methods with valid receivers and non-blank _ names
+       var fileScopes []*Scope
        for fileNo, file := range check.files {
                // The package identifier denotes the current package,
                // but there is no corresponding package object.
@@ -230,6 +236,7 @@ func (check *Checker) collectObjects() {
                        pos, end = token.Pos(f.Base()), token.Pos(f.Base()+f.Size())
                }
                fileScope := NewScope(check.pkg.scope, pos, end, check.filename(fileNo))
+               fileScopes = append(fileScopes, fileScope)
                check.recordScope(file, fileScope)
 
                // determine file directory, necessary to resolve imports
@@ -324,7 +331,7 @@ func (check *Checker) collectObjects() {
                                                init = d.init[i]
                                        }
 
-                                       d := &declInfo{file: fileScope, typ: d.typ, init: init, inherited: d.inherited}
+                                       d := &declInfo{file: fileScope, vtyp: d.typ, init: init, inherited: d.inherited}
                                        check.declarePkgObj(name, obj, d)
                                }
 
@@ -339,7 +346,7 @@ func (check *Checker) collectObjects() {
                                        // The lhs elements are only set up after the for loop below,
                                        // but that's ok because declareVar only collects the declInfo
                                        // for a later phase.
-                                       d1 = &declInfo{file: fileScope, lhs: lhs, typ: d.spec.Type, init: d.spec.Values[0]}
+                                       d1 = &declInfo{file: fileScope, lhs: lhs, vtyp: d.spec.Type, init: d.spec.Values[0]}
                                }
 
                                // declare all variables
@@ -354,26 +361,38 @@ func (check *Checker) collectObjects() {
                                                if i < len(d.spec.Values) {
                                                        init = d.spec.Values[i]
                                                }
-                                               di = &declInfo{file: fileScope, typ: d.spec.Type, init: init}
+                                               di = &declInfo{file: fileScope, vtyp: d.spec.Type, init: init}
                                        }
 
                                        check.declarePkgObj(name, obj, di)
                                }
                        case typeDecl:
                                obj := NewTypeName(d.spec.Name.Pos(), pkg, d.spec.Name.Name, nil)
-                               check.declarePkgObj(d.spec.Name, obj, &declInfo{file: fileScope, typ: d.spec.Type, alias: d.spec.Assign.IsValid()})
+                               check.declarePkgObj(d.spec.Name, obj, &declInfo{file: fileScope, tdecl: d.spec})
                        case funcDecl:
                                info := &declInfo{file: fileScope, fdecl: d.decl}
                                name := d.decl.Name.Name
                                obj := NewFunc(d.decl.Name.Pos(), pkg, name, nil)
-                               if d.decl.Recv == nil {
+                               if !d.decl.IsMethod() {
                                        // regular function
+                                       if d.decl.Recv != nil {
+                                               check.error(d.decl.Recv, _BadRecv, "method is missing receiver")
+                                               // treat as function
+                                       }
                                        if name == "init" {
+                                               if d.decl.Type.TParams != nil {
+                                                       check.softErrorf(d.decl.Type.TParams, _InvalidInitSig, "func init must have no type parameters")
+                                               }
+                                               if t := d.decl.Type; t.Params.NumFields() != 0 || t.Results != nil {
+                                                       // TODO(rFindley) Should this be a hard error?
+                                                       check.softErrorf(d.decl, _InvalidInitSig, "func init must have no arguments and no return values")
+                                               }
                                                // don't declare init functions in the package scope - they are invisible
                                                obj.parent = pkg.scope
                                                check.recordDef(d.decl.Name, obj)
                                                // init functions must have a body
                                                if d.decl.Body == nil {
+                                                       // TODO(gri) make this error message consistent with the others above
                                                        check.softErrorf(obj, _MissingInitBody, "missing function body")
                                                }
                                        } else {
@@ -381,11 +400,15 @@ func (check *Checker) collectObjects() {
                                        }
                                } else {
                                        // method
-                                       // (Methods with blank _ names are never found; no need to collect
-                                       // them for later type association. They will still be type-checked
-                                       // with all the other functions.)
-                                       if name != "_" {
-                                               methods = append(methods, obj)
+                                       if d.decl.Type.TParams != nil {
+                                               check.invalidAST(d.decl.Type.TParams, "method must have no type parameters")
+                                       }
+                                       ptr, recv, _ := check.unpackRecv(d.decl.Recv.List[0].Type, false)
+                                       // (Methods with invalid receiver cannot be associated to a type, and
+                                       // methods with blank _ names are never found; no need to collect any
+                                       // of them. They will still be type-checked with all the other functions.)
+                                       if recv != nil && name != "_" {
+                                               methods = append(methods, methodInfo{obj, ptr, recv})
                                        }
                                        check.recordDef(d.decl.Name, obj)
                                }
@@ -400,7 +423,7 @@ func (check *Checker) collectObjects() {
        }
 
        // verify that objects in package and file scopes have different names
-       for _, scope := range check.pkg.scope.children /* file scopes */ {
+       for _, scope := range fileScopes {
                for _, obj := range scope.elems {
                        if alt := pkg.scope.Lookup(obj.Name()); alt != nil {
                                if pkg, ok := obj.(*PkgName); ok {
@@ -423,31 +446,87 @@ func (check *Checker) collectObjects() {
                return // nothing to do
        }
        check.methods = make(map[*TypeName][]*Func)
-       for _, f := range methods {
-               fdecl := check.objMap[f].fdecl
-               if list := fdecl.Recv.List; len(list) > 0 {
-                       // f is a method.
-                       // Determine the receiver base type and associate f with it.
-                       ptr, base := check.resolveBaseTypeName(list[0].Type)
-                       if base != nil {
-                               f.hasPtrRecv = ptr
-                               check.methods[base] = append(check.methods[base], f)
+       for i := range methods {
+               m := &methods[i]
+               // Determine the receiver base type and associate m with it.
+               ptr, base := check.resolveBaseTypeName(m.ptr, m.recv)
+               if base != nil {
+                       m.obj.hasPtrRecv = ptr
+                       check.methods[base] = append(check.methods[base], m.obj)
+               }
+       }
+}
+
+// unpackRecv unpacks a receiver type and returns its components: ptr indicates whether
+// rtyp is a pointer receiver, rname is the receiver type name, and tparams are its
+// type parameters, if any. The type parameters are only unpacked if unpackParams is
+// set. If rname is nil, the receiver is unusable (i.e., the source has a bug which we
+// cannot easily work around).
+func (check *Checker) unpackRecv(rtyp ast.Expr, unpackParams bool) (ptr bool, rname *ast.Ident, tparams []*ast.Ident) {
+L: // unpack receiver type
+       // This accepts invalid receivers such as ***T and does not
+       // work for other invalid receivers, but we don't care. The
+       // validity of receiver expressions is checked elsewhere.
+       for {
+               switch t := rtyp.(type) {
+               case *ast.ParenExpr:
+                       rtyp = t.X
+               case *ast.StarExpr:
+                       ptr = true
+                       rtyp = t.X
+               default:
+                       break L
+               }
+       }
+
+       // unpack type parameters, if any
+       switch ptyp := rtyp.(type) {
+       case *ast.IndexExpr:
+               panic("unimplemented")
+       case *ast.CallExpr:
+               rtyp = ptyp.Fun
+               if unpackParams {
+                       for _, arg := range ptyp.Args {
+                               var par *ast.Ident
+                               switch arg := arg.(type) {
+                               case *ast.Ident:
+                                       par = arg
+                               case *ast.BadExpr:
+                                       // ignore - error already reported by parser
+                               case nil:
+                                       check.invalidAST(ptyp, "parameterized receiver contains nil parameters")
+                               default:
+                                       check.errorf(arg, 0, "receiver type parameter %s must be an identifier", arg)
+                               }
+                               if par == nil {
+                                       par = &ast.Ident{NamePos: arg.Pos(), Name: "_"}
+                               }
+                               tparams = append(tparams, par)
                        }
                }
        }
+
+       // unpack receiver name
+       if name, _ := rtyp.(*ast.Ident); name != nil {
+               rname = name
+       }
+
+       return
 }
 
 // resolveBaseTypeName returns the non-alias base type name for typ, and whether
 // there was a pointer indirection to get to it. The base type name must be declared
 // in package scope, and there can be at most one pointer indirection. If no such type
 // name exists, the returned base is nil.
-func (check *Checker) resolveBaseTypeName(typ ast.Expr) (ptr bool, base *TypeName) {
+func (check *Checker) resolveBaseTypeName(seenPtr bool, name *ast.Ident) (ptr bool, base *TypeName) {
        // Algorithm: Starting from a type expression, which may be a name,
        // we follow that type through alias declarations until we reach a
        // non-alias type name. If we encounter anything but pointer types or
        // parentheses we're done. If we encounter more than one pointer type
        // we're done.
+       ptr = seenPtr
        var seen map[*TypeName]bool
+       var typ ast.Expr = name
        for {
                typ = unparen(typ)
 
@@ -487,13 +566,13 @@ func (check *Checker) resolveBaseTypeName(typ ast.Expr) (ptr bool, base *TypeNam
 
                // we're done if tdecl defined tname as a new type
                // (rather than an alias)
-               tdecl := check.objMap[tname] // must exist for objects in package scope
-               if !tdecl.alias {
+               tdecl := check.objMap[tname].tdecl // must exist for objects in package scope
+               if !tdecl.Assign.IsValid() {
                        return ptr, tname
                }
 
                // otherwise, continue resolving
-               typ = tdecl.typ
+               typ = tdecl.Type
                if seen == nil {
                        seen = make(map[*TypeName]bool)
                }
@@ -515,7 +594,7 @@ func (check *Checker) packageObjects() {
        // add new methods to already type-checked types (from a prior Checker.Files call)
        for _, obj := range objList {
                if obj, _ := obj.(*TypeName); obj != nil && obj.typ != nil {
-                       check.addMethodDecls(obj)
+                       check.collectMethods(obj)
                }
        }
 
@@ -529,7 +608,7 @@ func (check *Checker) packageObjects() {
        // phase 1
        for _, obj := range objList {
                // If we have a type alias, collect it for the 2nd phase.
-               if tname, _ := obj.(*TypeName); tname != nil && check.objMap[tname].alias {
+               if tname, _ := obj.(*TypeName); tname != nil && check.objMap[tname].tdecl.Assign.IsValid() {
                        aliasList = append(aliasList, tname)
                        continue
                }
diff --git a/src/go/types/sanitize.go b/src/go/types/sanitize.go
new file mode 100644 (file)
index 0000000..c4e729e
--- /dev/null
@@ -0,0 +1,150 @@
+// Copyright 2020 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 types
+
+// sanitizeInfo walks the types contained in info to ensure that all instances
+// are expanded.
+func sanitizeInfo(info *Info) {
+       var s sanitizer = make(map[Type]Type)
+
+       // Note: Some map entries are not references.
+       // If modified, they must be assigned back.
+
+       for e, tv := range info.Types {
+               tv.Type = s.typ(tv.Type)
+               info.Types[e] = tv
+       }
+
+       for e, inf := range info.Inferred {
+               for i, targ := range inf.Targs {
+                       inf.Targs[i] = s.typ(targ)
+               }
+               inf.Sig = s.typ(inf.Sig).(*Signature)
+               info.Inferred[e] = inf
+       }
+
+       for _, obj := range info.Defs {
+               if obj != nil {
+                       obj.setType(s.typ(obj.Type()))
+               }
+       }
+
+       for _, obj := range info.Uses {
+               if obj != nil {
+                       obj.setType(s.typ(obj.Type()))
+               }
+       }
+
+       // TODO(gri) sanitize as needed
+       // - info.Implicits
+       // - info.Selections
+       // - info.Scopes
+       // - info.InitOrder
+}
+
+type sanitizer map[Type]Type
+
+func (s sanitizer) typ(typ Type) Type {
+       if t, found := s[typ]; found {
+               return t
+       }
+       s[typ] = typ
+
+       switch t := typ.(type) {
+       case nil, *Basic, *bottom, *top:
+               // nothing to do
+
+       case *Array:
+               t.elem = s.typ(t.elem)
+
+       case *Slice:
+               t.elem = s.typ(t.elem)
+
+       case *Struct:
+               s.varList(t.fields)
+
+       case *Pointer:
+               t.base = s.typ(t.base)
+
+       case *Tuple:
+               s.tuple(t)
+
+       case *Signature:
+               s.var_(t.recv)
+               s.tuple(t.params)
+               s.tuple(t.results)
+
+       case *Sum:
+               s.typeList(t.types)
+
+       case *Interface:
+               s.funcList(t.methods)
+               s.typ(t.types)
+               s.typeList(t.embeddeds)
+               s.funcList(t.allMethods)
+               s.typ(t.allTypes)
+
+       case *Map:
+               t.key = s.typ(t.key)
+               t.elem = s.typ(t.elem)
+
+       case *Chan:
+               t.elem = s.typ(t.elem)
+
+       case *Named:
+               t.orig = s.typ(t.orig)
+               t.underlying = s.typ(t.underlying)
+               s.typeList(t.targs)
+               s.funcList(t.methods)
+
+       case *TypeParam:
+               t.bound = s.typ(t.bound)
+
+       case *instance:
+               typ = t.expand()
+               s[t] = typ
+
+       default:
+               panic("unimplemented")
+       }
+
+       return typ
+}
+
+func (s sanitizer) var_(v *Var) {
+       if v != nil {
+               v.typ = s.typ(v.typ)
+       }
+}
+
+func (s sanitizer) varList(list []*Var) {
+       for _, v := range list {
+               s.var_(v)
+       }
+}
+
+func (s sanitizer) tuple(t *Tuple) {
+       if t != nil {
+               s.varList(t.vars)
+       }
+}
+
+func (s sanitizer) func_(f *Func) {
+       if f != nil {
+               f.typ = s.typ(f.typ)
+       }
+}
+
+func (s sanitizer) funcList(list []*Func) {
+       for _, f := range list {
+               s.func_(f)
+       }
+}
+
+func (s sanitizer) typeList(list []Type) {
+       for i, t := range list {
+               list[i] = s.typ(t)
+       }
+}
index 8c9d9ab8b8010be3674fd948e641048fdfe1d20d..157b1b70661d1e6fee217d54d06cd0ca83b6209f 100644 (file)
@@ -108,6 +108,40 @@ func (s *Scope) Insert(obj Object) Object {
        return nil
 }
 
+// Squash merges s with its parent scope p by adding all
+// objects of s to p, adding all children of s to the
+// children of p, and removing s from p's children.
+// The function f is called for each object obj in s which
+// has an object alt in p. s should be discarded after
+// having been squashed.
+func (s *Scope) Squash(err func(obj, alt Object)) {
+       p := s.parent
+       assert(p != nil)
+       for _, obj := range s.elems {
+               obj.setParent(nil)
+               if alt := p.Insert(obj); alt != nil {
+                       err(obj, alt)
+               }
+       }
+
+       j := -1 // index of s in p.children
+       for i, ch := range p.children {
+               if ch == s {
+                       j = i
+                       break
+               }
+       }
+       assert(j >= 0)
+       k := len(p.children) - 1
+       p.children[j] = p.children[k]
+       p.children = p.children[:k]
+
+       p.children = append(p.children, s.children...)
+
+       s.children = nil
+       s.elems = nil
+}
+
 // Pos and End describe the scope's source code extent [pos, end).
 // The results are guaranteed to be valid only if the type-checked
 // AST has complete position information. The extent is undefined
index 6ab6157b82df48749e67bc12157066b530e54cd2..e8377a4f9291756f79c75a6f6c5f96aa966d6ca5 100644 (file)
@@ -48,7 +48,7 @@ type StdSizes struct {
 func (s *StdSizes) Alignof(T Type) int64 {
        // For arrays and structs, alignment is defined in terms
        // of alignment of the elements and fields, respectively.
-       switch t := T.Underlying().(type) {
+       switch t := optype(T).(type) {
        case *Array:
                // spec: "For a variable x of array type: unsafe.Alignof(x)
                // is the same as unsafe.Alignof(x[0]), but at least 1."
@@ -118,7 +118,7 @@ var basicSizes = [...]byte{
 }
 
 func (s *StdSizes) Sizeof(T Type) int64 {
-       switch t := T.Underlying().(type) {
+       switch t := optype(T).(type) {
        case *Basic:
                assert(isTyped(T))
                k := t.kind
@@ -148,6 +148,8 @@ func (s *StdSizes) Sizeof(T Type) int64 {
                }
                offsets := s.Offsetsof(t.fields)
                return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
+       case *Sum:
+               panic("Sizeof unimplemented for type sum")
        case *Interface:
                return s.WordSize * 2
        }
@@ -239,7 +241,7 @@ func (conf *Config) offsetsof(T *Struct) []int64 {
 func (conf *Config) offsetof(typ Type, index []int) int64 {
        var o int64
        for _, i := range index {
-               s := typ.Underlying().(*Struct)
+               s := asStruct(typ)
                o += conf.offsetsof(s)[i]
                typ = s.fields[i].typ
        }
index d88e47170c3a676b3ffa83acebb82a27fbb0e5cf..a36ca430167e2ffb2238f3181c5fdc477321bf50 100644 (file)
@@ -147,7 +147,7 @@ func (check *Checker) multipleDefaults(list []ast.Stmt) {
        }
 }
 
-func (check *Checker) openScope(s ast.Stmt, comment string) {
+func (check *Checker) openScope(s ast.Node, comment string) {
        scope := NewScope(check.scope, s.Pos(), s.End(), comment)
        check.recordScope(s, scope)
        check.scope = scope
diff --git a/src/go/types/subst.go b/src/go/types/subst.go
new file mode 100644 (file)
index 0000000..ca9462d
--- /dev/null
@@ -0,0 +1,542 @@
+// Copyright 2018 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.
+
+// This file implements instantiation of generic types
+// through substitution of type parameters by actual
+// types.
+
+package types
+
+import (
+       "bytes"
+       "fmt"
+       "go/token"
+)
+
+// TODO(rFindley) decide error codes for the errors in this file, and check
+//                if error spans can be improved
+
+type substMap struct {
+       // The targs field is currently needed for *Named type substitution.
+       // TODO(gri) rewrite that code, get rid of this field, and make this
+       //           struct just the map (proj)
+       targs []Type
+       proj  map[*TypeParam]Type
+}
+
+// makeSubstMap creates a new substitution map mapping tpars[i] to targs[i].
+// If targs[i] is nil, tpars[i] is not substituted.
+func makeSubstMap(tpars []*TypeName, targs []Type) *substMap {
+       assert(len(tpars) == len(targs))
+       proj := make(map[*TypeParam]Type, len(tpars))
+       for i, tpar := range tpars {
+               // We must expand type arguments otherwise *instance
+               // types end up as components in composite types.
+               // TODO(gri) explain why this causes problems, if it does
+               targ := expand(targs[i]) // possibly nil
+               targs[i] = targ
+               proj[tpar.typ.(*TypeParam)] = targ
+       }
+       return &substMap{targs, proj}
+}
+
+func (m *substMap) String() string {
+       return fmt.Sprintf("%s", m.proj)
+}
+
+func (m *substMap) empty() bool {
+       return len(m.proj) == 0
+}
+
+func (m *substMap) lookup(tpar *TypeParam) Type {
+       if t := m.proj[tpar]; t != nil {
+               return t
+       }
+       return tpar
+}
+
+func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist []token.Pos) (res Type) {
+       if trace {
+               check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs))
+               check.indent++
+               defer func() {
+                       check.indent--
+                       var under Type
+                       if res != nil {
+                               // Calling under() here may lead to endless instantiations.
+                               // Test case: type T[P any] T[P]
+                               // TODO(gri) investigate if that's a bug or to be expected.
+                               under = res.Underlying()
+                       }
+                       check.trace(pos, "=> %s (under = %s)", res, under)
+               }()
+       }
+
+       assert(len(poslist) <= len(targs))
+
+       // TODO(gri) What is better here: work with TypeParams, or work with TypeNames?
+       var tparams []*TypeName
+       switch t := typ.(type) {
+       case *Named:
+               tparams = t.tparams
+       case *Signature:
+               tparams = t.tparams
+               defer func() {
+                       // If we had an unexpected failure somewhere don't panic below when
+                       // asserting res.(*Signature). Check for *Signature in case Typ[Invalid]
+                       // is returned.
+                       if _, ok := res.(*Signature); !ok {
+                               return
+                       }
+                       // 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).
+                       if t == res {
+                               copy := *t
+                               res = &copy
+                       }
+                       // After instantiating a generic signature, it is not generic
+                       // anymore; we need to set tparams to nil.
+                       res.(*Signature).tparams = nil
+               }()
+
+       default:
+               check.dump("%v: cannot instantiate %v", pos, typ)
+               unreachable() // only defined types and (defined) functions can be generic
+       }
+
+       // the number of supplied types must match the number of type parameters
+       if len(targs) != len(tparams) {
+               // TODO(gri) provide better error message
+               check.errorf(atPos(pos), 0, "got %d arguments but %d type parameters", len(targs), len(tparams))
+               return Typ[Invalid]
+       }
+
+       if len(tparams) == 0 {
+               return typ // nothing to do (minor optimization)
+       }
+
+       smap := makeSubstMap(tparams, targs)
+
+       // check bounds
+       for i, tname := range tparams {
+               tpar := tname.typ.(*TypeParam)
+               iface := tpar.Bound()
+               if iface.Empty() {
+                       continue // no type bound
+               }
+
+               targ := targs[i]
+
+               // best position for error reporting
+               pos := pos
+               if i < len(poslist) {
+                       pos = poslist[i]
+               }
+
+               // The type parameter bound is parameterized with the same type parameters
+               // as the instantiated type; before we can use it for bounds checking we
+               // need to instantiate it with the type arguments with which we instantiate
+               // the parameterized type.
+               iface = check.subst(pos, iface, smap).(*Interface)
+
+               // targ must implement iface (methods)
+               // - check only if we have methods
+               check.completeInterface(token.NoPos, iface)
+               if len(iface.allMethods) > 0 {
+                       // If the type argument is a pointer to a type parameter, the type argument's
+                       // method set is empty.
+                       // TODO(gri) is this what we want? (spec question)
+                       if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil {
+                               check.errorf(atPos(pos), 0, "%s has no methods", targ)
+                               break
+                       }
+                       if m, wrong := check.missingMethod(targ, iface, true); m != nil {
+                               // TODO(gri) needs to print updated name to avoid major confusion in error message!
+                               //           (print warning for now)
+                               // Old warning:
+                               // check.softErrorf(pos, "%s does not satisfy %s (warning: name not updated) = %s (missing method %s)", targ, tpar.bound, iface, m)
+                               if m.name == "==" {
+                                       // We don't want to report "missing method ==".
+                                       check.softErrorf(atPos(pos), 0, "%s does not satisfy comparable", targ)
+                               } else if wrong != nil {
+                                       // TODO(gri) This can still report uninstantiated types which makes the error message
+                                       //           more difficult to read then necessary.
+                                       check.softErrorf(atPos(pos), 0,
+                                               "%s does not satisfy %s: wrong method signature\n\tgot  %s\n\twant %s",
+                                               targ, tpar.bound, wrong, m,
+                                       )
+                               } else {
+                                       check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name)
+                               }
+                               break
+                       }
+               }
+
+               // targ's underlying type must also be one of the interface types listed, if any
+               if iface.allTypes == nil {
+                       continue // nothing to do
+               }
+
+               // If targ is itself a type parameter, each of its possible types, but at least one, must be in the
+               // list of iface types (i.e., the targ type list must be a non-empty subset of the iface types).
+               if targ := asTypeParam(targ); targ != nil {
+                       targBound := targ.Bound()
+                       if targBound.allTypes == nil {
+                               check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ)
+                               break
+                       }
+                       for _, t := range unpackType(targBound.allTypes) {
+                               if !iface.isSatisfiedBy(t) {
+                                       // TODO(gri) match this error message with the one below (or vice versa)
+                                       check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes)
+                                       break
+                               }
+                       }
+                       break
+               }
+
+               // Otherwise, targ's type or underlying type must also be one of the interface types listed, if any.
+               if !iface.isSatisfiedBy(targ) {
+                       check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s or %s not found in %s)", targ, tpar.bound, targ, under(targ), iface.allTypes)
+                       break
+               }
+       }
+
+       return check.subst(pos, typ, smap)
+}
+
+// subst returns the type typ with its type parameters tpars replaced by
+// the corresponding type arguments targs, recursively.
+// subst is functional in the sense that it doesn't modify the incoming
+// type. If a substitution took place, the result type is different from
+// from the incoming type.
+func (check *Checker) subst(pos token.Pos, typ Type, smap *substMap) Type {
+       if smap.empty() {
+               return typ
+       }
+
+       // common cases
+       switch t := typ.(type) {
+       case *Basic:
+               return typ // nothing to do
+       case *TypeParam:
+               return smap.lookup(t)
+       }
+
+       // general case
+       subst := subster{check, pos, make(map[Type]Type), smap}
+       return subst.typ(typ)
+}
+
+type subster struct {
+       check *Checker
+       pos   token.Pos
+       cache map[Type]Type
+       smap  *substMap
+}
+
+func (subst *subster) typ(typ Type) Type {
+       switch t := typ.(type) {
+       case nil:
+               // Call typOrNil if it's possible that typ is nil.
+               panic("nil typ")
+
+       case *Basic, *bottom, *top:
+               // nothing to do
+
+       case *Array:
+               elem := subst.typOrNil(t.elem)
+               if elem != t.elem {
+                       return &Array{len: t.len, elem: elem}
+               }
+
+       case *Slice:
+               elem := subst.typOrNil(t.elem)
+               if elem != t.elem {
+                       return &Slice{elem: elem}
+               }
+
+       case *Struct:
+               if fields, copied := subst.varList(t.fields); copied {
+                       return &Struct{fields: fields, tags: t.tags}
+               }
+
+       case *Pointer:
+               base := subst.typ(t.base)
+               if base != t.base {
+                       return &Pointer{base: base}
+               }
+
+       case *Tuple:
+               return subst.tuple(t)
+
+       case *Signature:
+               // TODO(gri) rethink the recv situation with respect to methods on parameterized types
+               // recv := subst.var_(t.recv) // TODO(gri) this causes a stack overflow - explain
+               recv := t.recv
+               params := subst.tuple(t.params)
+               results := subst.tuple(t.results)
+               if recv != t.recv || params != t.params || results != t.results {
+                       return &Signature{
+                               rparams: t.rparams,
+                               // TODO(rFindley) why can't we nil out tparams here, rather than in
+                               //                instantiate above?
+                               tparams:  t.tparams,
+                               scope:    t.scope,
+                               recv:     recv,
+                               params:   params,
+                               results:  results,
+                               variadic: t.variadic,
+                       }
+               }
+
+       case *Sum:
+               types, copied := subst.typeList(t.types)
+               if copied {
+                       // Don't do it manually, with a Sum literal: the new
+                       // types list may not be unique and NewSum may remove
+                       // duplicates.
+                       return NewSum(types)
+               }
+
+       case *Interface:
+               methods, mcopied := subst.funcList(t.methods)
+               types := t.types
+               if t.types != nil {
+                       types = subst.typ(t.types)
+               }
+               embeddeds, ecopied := subst.typeList(t.embeddeds)
+               if mcopied || types != t.types || ecopied {
+                       iface := &Interface{methods: methods, types: types, embeddeds: embeddeds}
+                       subst.check.posMap[iface] = subst.check.posMap[t] // satisfy completeInterface requirement
+                       subst.check.completeInterface(token.NoPos, iface)
+                       return iface
+               }
+
+       case *Map:
+               key := subst.typ(t.key)
+               elem := subst.typ(t.elem)
+               if key != t.key || elem != t.elem {
+                       return &Map{key: key, elem: elem}
+               }
+
+       case *Chan:
+               elem := subst.typ(t.elem)
+               if elem != t.elem {
+                       return &Chan{dir: t.dir, elem: elem}
+               }
+
+       case *Named:
+               subst.check.indent++
+               defer func() {
+                       subst.check.indent--
+               }()
+               dump := func(format string, args ...interface{}) {
+                       if trace {
+                               subst.check.trace(subst.pos, format, args...)
+                       }
+               }
+
+               if t.tparams == nil {
+                       dump(">>> %s is not parameterized", t)
+                       return t // type is not parameterized
+               }
+
+               var newTargs []Type
+
+               if len(t.targs) > 0 {
+                       // already instantiated
+                       dump(">>> %s already instantiated", t)
+                       assert(len(t.targs) == len(t.tparams))
+                       // For each (existing) type argument targ, determine if it needs
+                       // to be substituted; i.e., if it is or contains a type parameter
+                       // that has a type argument for it.
+                       for i, targ := range t.targs {
+                               dump(">>> %d targ = %s", i, targ)
+                               newTarg := subst.typ(targ)
+                               if newTarg != targ {
+                                       dump(">>> substituted %d targ %s => %s", i, targ, newTarg)
+                                       if newTargs == nil {
+                                               newTargs = make([]Type, len(t.tparams))
+                                               copy(newTargs, t.targs)
+                                       }
+                                       newTargs[i] = newTarg
+                               }
+                       }
+
+                       if newTargs == nil {
+                               dump(">>> nothing to substitute in %s", t)
+                               return t // nothing to substitute
+                       }
+               } else {
+                       // not yet instantiated
+                       dump(">>> first instantiation of %s", t)
+                       // TODO(rFindley) can we instead subst the tparam types here?
+                       newTargs = subst.smap.targs
+               }
+
+               // before creating a new named type, check if we have this one already
+               h := instantiatedHash(t, newTargs)
+               dump(">>> new type hash: %s", h)
+               if named, found := subst.check.typMap[h]; found {
+                       dump(">>> found %s", named)
+                       subst.cache[t] = named
+                       return named
+               }
+
+               // create a new named type and populate caches to avoid endless recursion
+               tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil)
+               named := subst.check.NewNamed(tname, t.underlying, t.methods) // method signatures are updated lazily
+               named.tparams = t.tparams                                     // new type is still parameterized
+               named.targs = newTargs
+               subst.check.typMap[h] = named
+               subst.cache[t] = named
+
+               // do the substitution
+               dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTargs)
+               named.underlying = subst.typOrNil(t.underlying)
+               named.orig = named.underlying // for cycle detection (Checker.validType)
+
+               return named
+
+       case *TypeParam:
+               return subst.smap.lookup(t)
+
+       case *instance:
+               // TODO(gri) can we avoid the expansion here and just substitute the type parameters?
+               return subst.typ(t.expand())
+
+       default:
+               panic("unimplemented")
+       }
+
+       return typ
+}
+
+// TODO(gri) Eventually, this should be more sophisticated.
+//           It won't work correctly for locally declared types.
+func instantiatedHash(typ *Named, targs []Type) string {
+       var buf bytes.Buffer
+       writeTypeName(&buf, typ.obj, nil)
+       buf.WriteByte('[')
+       writeTypeList(&buf, targs, nil, nil)
+       buf.WriteByte(']')
+
+       // With respect to the represented type, whether a
+       // type is fully expanded or stored as instance
+       // does not matter - they are the same types.
+       // Remove the instanceMarkers printed for instances.
+       res := buf.Bytes()
+       i := 0
+       for _, b := range res {
+               if b != instanceMarker {
+                       res[i] = b
+                       i++
+               }
+       }
+
+       return string(res[:i])
+}
+
+func typeListString(list []Type) string {
+       var buf bytes.Buffer
+       writeTypeList(&buf, list, nil, nil)
+       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.
+func (subst *subster) typOrNil(typ Type) Type {
+       if typ == nil {
+               return Typ[Invalid]
+       }
+       return subst.typ(typ)
+}
+
+func (subst *subster) var_(v *Var) *Var {
+       if v != nil {
+               if typ := subst.typ(v.typ); typ != v.typ {
+                       copy := *v
+                       copy.typ = typ
+                       return &copy
+               }
+       }
+       return v
+}
+
+func (subst *subster) tuple(t *Tuple) *Tuple {
+       if t != nil {
+               if vars, copied := subst.varList(t.vars); copied {
+                       return &Tuple{vars: vars}
+               }
+       }
+       return t
+}
+
+func (subst *subster) varList(in []*Var) (out []*Var, copied bool) {
+       out = in
+       for i, v := range in {
+               if w := subst.var_(v); w != v {
+                       if !copied {
+                               // first variable that got substituted => allocate new out slice
+                               // and copy all variables
+                               new := make([]*Var, len(in))
+                               copy(new, out)
+                               out = new
+                               copied = true
+                       }
+                       out[i] = w
+               }
+       }
+       return
+}
+
+func (subst *subster) func_(f *Func) *Func {
+       if f != nil {
+               if typ := subst.typ(f.typ); typ != f.typ {
+                       copy := *f
+                       copy.typ = typ
+                       return &copy
+               }
+       }
+       return f
+}
+
+func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) {
+       out = in
+       for i, f := range in {
+               if g := subst.func_(f); g != f {
+                       if !copied {
+                               // first function that got substituted => allocate new out slice
+                               // and copy all functions
+                               new := make([]*Func, len(in))
+                               copy(new, out)
+                               out = new
+                               copied = true
+                       }
+                       out[i] = g
+               }
+       }
+       return
+}
+
+func (subst *subster) typeList(in []Type) (out []Type, copied bool) {
+       out = in
+       for i, t := range in {
+               if u := subst.typ(t); u != t {
+                       if !copied {
+                               // first function that got substituted => allocate new out slice
+                               // and copy all functions
+                               new := make([]Type, len(in))
+                               copy(new, out)
+                               out = new
+                               copied = true
+                       }
+                       out[i] = u
+               }
+       }
+       return
+}
index 5501b659153a83a899f40f1dbaf1e77d0594d7f5..5ad8f53f65ab20b5e21b753119df153a67bd206b 100644 (file)
@@ -184,11 +184,13 @@ func f1(x f1 /* ERROR "not a type" */ ) {}
 func f2(x *f2 /* ERROR "not a type" */ ) {}
 func f3() (x f3 /* ERROR "not a type" */ ) { return }
 func f4() (x *f4 /* ERROR "not a type" */ ) { return }
+// TODO(#43215) this should be detected as a cycle error
+func f5([unsafe.Sizeof(f5)]int) {}
 
-func (S0) m1 /* ERROR illegal cycle */ (x S0 /* ERROR value .* is not a type */ .m1) {}
-func (S0) m2 /* ERROR illegal cycle */ (x *S0 /* ERROR value .* is not a type */ .m2) {}
-func (S0) m3 /* ERROR illegal cycle */ () (x S0 /* ERROR value .* is not a type */ .m3) { return }
-func (S0) m4 /* ERROR illegal cycle */ () (x *S0 /* ERROR value .* is not a type */ .m4) { return }
+func (S0) m1 (x S0 /* ERROR value .* is not a type */ .m1) {}
+func (S0) m2 (x *S0 /* ERROR value .* is not a type */ .m2) {}
+func (S0) m3 () (x S0 /* ERROR value .* is not a type */ .m3) { return }
+func (S0) m4 () (x *S0 /* ERROR value .* is not a type */ .m4) { return }
 
 // interfaces may not have any blank methods
 type BlankI interface {
index e0c5d7a37cf48f339273e849b07e9c88c2610aec..db415eadfbf7080eccbbd67b07afdc6a1f7f1953 100644 (file)
@@ -325,8 +325,8 @@ func issue28281c(a, b, c ... /* ERROR can only use ... with final parameter */ i
 func issue28281d(... /* ERROR can only use ... with final parameter */ int, int)
 func issue28281e(a, b, c  ... /* ERROR can only use ... with final parameter */ int, d int)
 func issue28281f(... /* ERROR can only use ... with final parameter */ int, ... /* ERROR can only use ... with final parameter */ int, int)
-func (... /* ERROR expected type */ TT) f()
-func issue28281g() (... /* ERROR expected type */ TT)
+func (... /* ERROR can only use ... with final parameter */ TT) f()
+func issue28281g() (... /* ERROR can only use ... with final parameter */ TT)
 
 // Issue #26234: Make various field/method lookup errors easier to read by matching cmd/compile's output
 func issue26234a(f *syn.File) {
index 087cda429d689ab83c714a5f18caef0fdd442e16..0fcefefb7348b0018c0e7be05281b2b1f1e7817f 100644 (file)
@@ -4,12 +4,18 @@
 
 package types
 
-import "sort"
+import (
+       "fmt"
+       "go/token"
+       "sort"
+)
 
 // A Type represents a type of Go.
 // All types implement the Type interface.
 type Type interface {
-       // Underlying returns the underlying type of a type.
+       // Underlying returns the underlying type of a type
+       // w/o following forwarding chains. Only used by
+       // client packages (here for backward-compatibility).
        Underlying() Type
 
        // String returns a string representation of a type.
@@ -98,7 +104,7 @@ type Array struct {
 
 // NewArray returns a new array type for the given element type and length.
 // A negative length indicates an unknown length.
-func NewArray(elem Type, len int64) *Array { return &Array{len, elem} }
+func NewArray(elem Type, len int64) *Array { return &Array{len: len, elem: elem} }
 
 // Len returns the length of array a.
 // A negative result indicates an unknown length.
@@ -113,7 +119,7 @@ type Slice struct {
 }
 
 // NewSlice returns a new slice type for the given element type.
-func NewSlice(elem Type) *Slice { return &Slice{elem} }
+func NewSlice(elem Type) *Slice { return &Slice{elem: elem} }
 
 // Elem returns the element type of slice s.
 func (s *Slice) Elem() Type { return s.elem }
@@ -176,8 +182,10 @@ type Tuple struct {
 // NewTuple returns a new tuple for the given variables.
 func NewTuple(x ...*Var) *Tuple {
        if len(x) > 0 {
-               return &Tuple{x}
+               return &Tuple{vars: x}
        }
+       // TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer;
+       //           it's too subtle and causes problems.
        return nil
 }
 
@@ -199,11 +207,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.
-       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  []*TypeName // receiver type parameters from left to right, or nil
+       tparams  []*TypeName // 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,
@@ -220,7 +230,7 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
                        panic("types.NewSignature: variadic parameter must be of unnamed slice type")
                }
        }
-       return &Signature{nil, recv, params, results, variadic}
+       return &Signature{recv: recv, params: params, results: results, variadic: variadic}
 }
 
 // Recv returns the receiver of signature s (if a method), or nil if a
@@ -231,6 +241,12 @@ 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() []*TypeName { return s.tparams }
+
+// SetTParams sets the type parameters of signature s.
+func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = tparams }
+
 // Params returns the parameters of signature s, or nil.
 func (s *Signature) Params() *Tuple { return s.params }
 
@@ -240,12 +256,88 @@ func (s *Signature) Results() *Tuple { return s.results }
 // Variadic reports whether the signature s is variadic.
 func (s *Signature) Variadic() bool { return s.variadic }
 
+// A Sum represents a set of possible types.
+// Sums are currently used to represent type lists of interfaces
+// and thus the underlying types of type parameters; they are not
+// first class types of Go.
+type Sum struct {
+       types []Type // types are unique
+}
+
+// NewSum returns a new Sum type consisting of the provided
+// types if there are more than one. If there is exactly one
+// type, it returns that type. If the list of types is empty
+// the result is nil.
+func NewSum(types []Type) Type {
+       if len(types) == 0 {
+               return nil
+       }
+
+       // What should happen if types contains a sum type?
+       // Do we flatten the types list? For now we check
+       // and panic. This should not be possible for the
+       // current use case of type lists.
+       // TODO(gri) Come up with the rules for sum types.
+       for _, t := range types {
+               if _, ok := t.(*Sum); ok {
+                       panic("sum type contains sum type - unimplemented")
+               }
+       }
+
+       if len(types) == 1 {
+               return types[0]
+       }
+       return &Sum{types: types}
+}
+
+// is reports whether all types in t satisfy pred.
+func (s *Sum) is(pred func(Type) bool) bool {
+       if s == nil {
+               return false
+       }
+       for _, t := range s.types {
+               if !pred(t) {
+                       return false
+               }
+       }
+       return true
+}
+
 // An Interface represents an interface type.
 type Interface struct {
        methods   []*Func // ordered list of explicitly declared methods
+       types     Type    // (possibly a Sum) type declared with a type list (TODO(gri) need better field name)
        embeddeds []Type  // ordered list of explicitly embedded types
 
        allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset)
+       allTypes   Type    // intersection of all embedded and locally declared types  (TODO(gri) need better field name)
+
+       obj Object // type declaration defining this interface; or nil (for better error messages)
+}
+
+// unpack unpacks a type into a list of types.
+// TODO(gri) Try to eliminate the need for this function.
+func unpackType(typ Type) []Type {
+       if typ == nil {
+               return nil
+       }
+       if sum := asSum(typ); sum != nil {
+               return sum.types
+       }
+       return []Type{typ}
+}
+
+// is reports whether interface t represents types that all satisfy pred.
+func (t *Interface) is(pred func(Type) bool) bool {
+       if t.allTypes == nil {
+               return false // we must have at least one type! (was bug)
+       }
+       for _, t := range unpackType(t.allTypes) {
+               if !pred(t) {
+                       return false
+               }
+       }
+       return true
 }
 
 // emptyInterface represents the empty (completed) interface
@@ -344,8 +436,101 @@ func (t *Interface) assertCompleteness() {
 func (t *Interface) Method(i int) *Func { t.assertCompleteness(); return t.allMethods[i] }
 
 // Empty reports whether t is the empty interface.
-// The interface must have been completed.
-func (t *Interface) Empty() bool { t.assertCompleteness(); return len(t.allMethods) == 0 }
+func (t *Interface) Empty() bool {
+       if t.allMethods != nil {
+               // interface is complete - quick test
+               // A non-nil allTypes may still be empty and represents the bottom type.
+               return len(t.allMethods) == 0 && t.allTypes == nil
+       }
+       return !t.iterate(func(t *Interface) bool {
+               return len(t.methods) > 0 || t.types != nil
+       }, nil)
+}
+
+// HasTypeList reports whether interface t has a type list, possibly from an embedded type.
+func (t *Interface) HasTypeList() bool {
+       if t.allMethods != nil {
+               // interface is complete - quick test
+               return t.allTypes != nil
+       }
+
+       return t.iterate(func(t *Interface) bool {
+               return t.types != nil
+       }, nil)
+}
+
+// IsComparable reports whether interface t is or embeds the predeclared interface "comparable".
+func (t *Interface) IsComparable() bool {
+       if t.allMethods != nil {
+               // interface is complete - quick test
+               _, m := lookupMethod(t.allMethods, nil, "==")
+               return m != nil
+       }
+
+       return t.iterate(func(t *Interface) bool {
+               _, m := lookupMethod(t.methods, nil, "==")
+               return m != nil
+       }, nil)
+}
+
+// IsConstraint reports t.HasTypeList() || t.IsComparable().
+func (t *Interface) IsConstraint() bool {
+       if t.allMethods != nil {
+               // interface is complete - quick test
+               if t.allTypes != nil {
+                       return true
+               }
+               _, m := lookupMethod(t.allMethods, nil, "==")
+               return m != nil
+       }
+
+       return t.iterate(func(t *Interface) bool {
+               if t.types != nil {
+                       return true
+               }
+               _, m := lookupMethod(t.methods, nil, "==")
+               return m != nil
+       }, nil)
+}
+
+// iterate calls f with t and then with any embedded interface of t, recursively, until f returns true.
+// iterate reports whether any call to f returned true.
+func (t *Interface) iterate(f func(*Interface) bool, seen map[*Interface]bool) bool {
+       if f(t) {
+               return true
+       }
+       for _, e := range t.embeddeds {
+               // e should be an interface but be careful (it may be invalid)
+               if e := asInterface(e); e != nil {
+                       // Cyclic interfaces such as "type E interface { E }" are not permitted
+                       // but they are still constructed and we need to detect such cycles.
+                       if seen[e] {
+                               continue
+                       }
+                       if seen == nil {
+                               seen = make(map[*Interface]bool)
+                       }
+                       seen[e] = true
+                       if e.iterate(f, seen) {
+                               return true
+                       }
+               }
+       }
+       return false
+}
+
+// isSatisfiedBy reports whether interface t's type list is satisfied by the type typ.
+// If the the type list is empty (absent), typ trivially satisfies the interface.
+// TODO(gri) This is not a great name. Eventually, we should have a more comprehensive
+//           "implements" predicate.
+func (t *Interface) isSatisfiedBy(typ Type) bool {
+       t.Complete()
+       if t.allTypes == nil {
+               return true
+       }
+       types := unpackType(t.allTypes)
+       return includes(types, typ) || includes(types, under(typ))
+}
 
 // Complete computes the interface's method set. It must be called by users of
 // NewInterfaceType and NewInterface after the interface's embedded types are
@@ -379,12 +564,22 @@ func (t *Interface) Complete() *Interface {
                addMethod(m, true)
        }
 
+       allTypes := t.types
+
        for _, typ := range t.embeddeds {
-               typ := typ.Underlying().(*Interface)
-               typ.Complete()
-               for _, m := range typ.allMethods {
+               utyp := under(typ)
+               etyp := asInterface(utyp)
+               if etyp == nil {
+                       if utyp != Typ[Invalid] {
+                               panic(fmt.Sprintf("%s is not an interface", typ))
+                       }
+                       continue
+               }
+               etyp.Complete()
+               for _, m := range etyp.allMethods {
                        addMethod(m, false)
                }
+               allTypes = intersect(allTypes, etyp.allTypes)
        }
 
        for i := 0; i < len(todo); i += 2 {
@@ -399,6 +594,7 @@ func (t *Interface) Complete() *Interface {
                sort.Sort(byUniqueMethodName(methods))
                t.allMethods = methods
        }
+       t.allTypes = allTypes
 
        return t
 }
@@ -410,7 +606,7 @@ type Map struct {
 
 // NewMap returns a new map for the given key and element types.
 func NewMap(key, elem Type) *Map {
-       return &Map{key, elem}
+       return &Map{key: key, elem: elem}
 }
 
 // Key returns the key type of map m.
@@ -437,7 +633,7 @@ const (
 
 // NewChan returns a new channel type for the given direction and element type.
 func NewChan(dir ChanDir, elem Type) *Chan {
-       return &Chan{dir, elem}
+       return &Chan{dir: dir, elem: elem}
 }
 
 // Dir returns the direction of channel c.
@@ -446,13 +642,16 @@ func (c *Chan) Dir() ChanDir { return c.dir }
 // Elem returns the element type of channel c.
 func (c *Chan) Elem() Type { return c.elem }
 
-// A Named represents a named type.
+// A Named represents a named (defined) type.
 type Named struct {
-       info       typeInfo  // for cycle detection
-       obj        *TypeName // corresponding declared object
-       orig       Type      // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
-       underlying Type      // possibly a *Named during setup; never a *Named once set up completely
-       methods    []*Func   // methods declared for this type (not the method set of this type); signatures are type-checked lazily
+       check      *Checker    // for Named.under implementation
+       info       typeInfo    // for cycle detection
+       obj        *TypeName   // corresponding declared object
+       orig       Type        // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
+       underlying Type        // possibly a *Named during setup; never a *Named once set up completely
+       tparams    []*TypeName // type parameters, or nil
+       targs      []Type      // 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
 }
 
 // NewNamed returns a new named type for the given type name, underlying type, and associated methods.
@@ -469,9 +668,30 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
        return typ
 }
 
+func (check *Checker) NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
+       typ := &Named{check: check, obj: obj, orig: underlying, underlying: underlying, methods: methods}
+       if obj.typ == nil {
+               obj.typ = typ
+       }
+       return typ
+}
+
 // Obj returns the type name for the named type t.
 func (t *Named) Obj() *TypeName { return t.obj }
 
+// 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.
+// The result is non-nil for an (originally) parameterized type even if it is instantiated.
+func (t *Named) TParams() []*TypeName { return t.tparams }
+
+// TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated.
+func (t *Named) TArgs() []Type { return t.targs }
+
+// SetTArgs sets the type arguments of Named.
+func (t *Named) SetTArgs(args []Type) { t.targs = args }
+
 // NumMethods returns the number of explicit methods whose receiver is named type t.
 func (t *Named) NumMethods() int { return len(t.methods) }
 
@@ -496,28 +716,261 @@ func (t *Named) AddMethod(m *Func) {
        }
 }
 
-// Implementations for Type methods.
+// A TypeParam represents a type parameter type.
+type TypeParam struct {
+       check *Checker  // for lazy type bound completion
+       id    uint64    // unique id
+       obj   *TypeName // corresponding type name
+       index int       // parameter index
+       bound Type      // *Named or *Interface; underlying type is always *Interface
+}
 
-func (b *Basic) Underlying() Type     { return b }
-func (a *Array) Underlying() Type     { return a }
-func (s *Slice) Underlying() Type     { return s }
-func (s *Struct) Underlying() Type    { return s }
-func (p *Pointer) Underlying() Type   { return p }
+// NewTypeParam returns a new TypeParam.
+func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam {
+       assert(bound != nil)
+       typ := &TypeParam{check: check, id: check.nextId, obj: obj, index: index, bound: bound}
+       check.nextId++
+       if obj.typ == nil {
+               obj.typ = typ
+       }
+       return typ
+}
+
+func (t *TypeParam) Bound() *Interface {
+       iface := asInterface(t.bound)
+       // use the type bound position if we have one
+       pos := token.NoPos
+       if n, _ := t.bound.(*Named); n != nil {
+               pos = n.obj.pos
+       }
+       // TODO(rFindley) switch this to an unexported method on Checker.
+       t.check.completeInterface(pos, iface)
+       return iface
+}
+
+// optype returns a type's operational type. Except for
+// type parameters, the operational type is the same
+// as the underlying type (as returned by under). For
+// Type parameters, the operational type is determined
+// by the corresponding type bound's type list. The
+// result may be the bottom or top type, but it is never
+// the incoming type parameter.
+func optype(typ Type) Type {
+       if t := asTypeParam(typ); t != nil {
+               // If the optype is typ, return the top type as we have
+               // no information. It also prevents infinite recursion
+               // via the asTypeParam converter function. This can happen
+               // for a type parameter list of the form:
+               // (type T interface { type T }).
+               // See also issue #39680.
+               if u := t.Bound().allTypes; u != nil && u != typ {
+                       // u != typ and u is a type parameter => under(u) != typ, so this is ok
+                       return under(u)
+               }
+               return theTop
+       }
+       return under(typ)
+}
+
+// An instance represents an instantiated generic type syntactically
+// (without expanding the instantiation). Type instances appear only
+// during type-checking and are replaced by their fully instantiated
+// (expanded) types before the end of type-checking.
+type instance struct {
+       check   *Checker    // for lazy instantiation
+       pos     token.Pos   // position of type instantiation; for error reporting only
+       base    *Named      // parameterized type to be instantiated
+       targs   []Type      // type arguments
+       poslist []token.Pos // position of each targ; for error reporting only
+       value   Type        // base(targs...) after instantiation or Typ[Invalid]; nil if not yet set
+}
+
+// expand returns the instantiated (= expanded) type of t.
+// The result is either an instantiated *Named type, or
+// Typ[Invalid] if there was an error.
+func (t *instance) expand() Type {
+       v := t.value
+       if v == nil {
+               v = t.check.instantiate(t.pos, t.base, t.targs, t.poslist)
+               if v == nil {
+                       v = Typ[Invalid]
+               }
+               t.value = v
+       }
+       // After instantiation we must have an invalid or a *Named type.
+       if debug && v != Typ[Invalid] {
+               _ = v.(*Named)
+       }
+       return v
+}
+
+// expand expands a type instance into its instantiated
+// type and leaves all other types alone. expand does
+// not recurse.
+func expand(typ Type) Type {
+       if t, _ := typ.(*instance); t != nil {
+               return t.expand()
+       }
+       return typ
+}
+
+// expandf is set to expand.
+// Call expandf when calling expand causes compile-time cycle error.
+var expandf func(Type) Type
+
+func init() { expandf = expand }
+
+// bottom represents the bottom of the type lattice.
+// It is the underlying type of a type parameter that
+// cannot be satisfied by any type, usually because
+// the intersection of type constraints left nothing).
+type bottom struct{}
+
+// theBottom is the singleton bottom type.
+var theBottom = &bottom{}
+
+// top represents the top of the type lattice.
+// It is the underlying type of a type parameter that
+// can be satisfied by any type (ignoring methods),
+// usually because the type constraint has no type
+// list.
+type top struct{}
+
+// theTop is the singleton top type.
+var theTop = &top{}
+
+// Type-specific implementations of Underlying.
+func (t *Basic) Underlying() Type     { return t }
+func (t *Array) Underlying() Type     { return t }
+func (t *Slice) Underlying() Type     { return t }
+func (t *Struct) Underlying() Type    { return t }
+func (t *Pointer) Underlying() Type   { return t }
 func (t *Tuple) Underlying() Type     { return t }
-func (s *Signature) Underlying() Type { return s }
+func (t *Signature) Underlying() Type { return t }
+func (t *Sum) Underlying() Type       { return t }
 func (t *Interface) Underlying() Type { return t }
-func (m *Map) Underlying() Type       { return m }
-func (c *Chan) Underlying() Type      { return c }
+func (t *Map) Underlying() Type       { return t }
+func (t *Chan) Underlying() Type      { return t }
 func (t *Named) Underlying() Type     { return t.underlying }
-
-func (b *Basic) String() string     { return TypeString(b, nil) }
-func (a *Array) String() string     { return TypeString(a, nil) }
-func (s *Slice) String() string     { return TypeString(s, nil) }
-func (s *Struct) String() string    { return TypeString(s, nil) }
-func (p *Pointer) String() string   { return TypeString(p, nil) }
+func (t *TypeParam) Underlying() Type { return t }
+func (t *instance) Underlying() Type  { return t }
+func (t *bottom) Underlying() Type    { return t }
+func (t *top) Underlying() Type       { return t }
+
+// Type-specific implementations of String.
+func (t *Basic) String() string     { return TypeString(t, nil) }
+func (t *Array) String() string     { return TypeString(t, nil) }
+func (t *Slice) String() string     { return TypeString(t, nil) }
+func (t *Struct) String() string    { return TypeString(t, nil) }
+func (t *Pointer) String() string   { return TypeString(t, nil) }
 func (t *Tuple) String() string     { return TypeString(t, nil) }
-func (s *Signature) String() string { return TypeString(s, nil) }
+func (t *Signature) String() string { return TypeString(t, nil) }
+func (t *Sum) String() string       { return TypeString(t, nil) }
 func (t *Interface) String() string { return TypeString(t, nil) }
-func (m *Map) String() string       { return TypeString(m, nil) }
-func (c *Chan) String() string      { return TypeString(c, nil) }
+func (t *Map) String() string       { return TypeString(t, nil) }
+func (t *Chan) String() string      { return TypeString(t, nil) }
 func (t *Named) String() string     { return TypeString(t, nil) }
+func (t *TypeParam) String() string { return TypeString(t, nil) }
+func (t *instance) String() string  { return TypeString(t, nil) }
+func (t *bottom) String() string    { return TypeString(t, nil) }
+func (t *top) String() string       { return TypeString(t, nil) }
+
+// under returns the true expanded underlying type.
+// If it doesn't exist, the result is Typ[Invalid].
+// under must only be called when a type is known
+// to be fully set up.
+func under(t Type) Type {
+       // TODO(gri) is this correct for *Sum?
+       if n := asNamed(t); n != nil {
+               return n.under()
+       }
+       return t
+}
+
+// Converters
+//
+// A converter must only be called when a type is
+// known to be fully set up. A converter returns
+// a type's operational type (see comment for optype)
+// or nil if the type argument is not of the
+// respective type.
+
+func asBasic(t Type) *Basic {
+       op, _ := optype(t).(*Basic)
+       return op
+}
+
+func asArray(t Type) *Array {
+       op, _ := optype(t).(*Array)
+       return op
+}
+
+func asSlice(t Type) *Slice {
+       op, _ := optype(t).(*Slice)
+       return op
+}
+
+// TODO (rFindley) delete this on the dev.typeparams branch. This is only
+// exported in the prototype for legacy compatibility.
+func AsStruct(t Type) *Struct {
+       return asStruct(t)
+}
+
+func asStruct(t Type) *Struct {
+       op, _ := optype(t).(*Struct)
+       return op
+}
+
+// TODO(rFindley) delete this on the dev.typeparams branch (see ToStruct).
+func AsPointer(t Type) *Pointer {
+       return asPointer(t)
+}
+
+func asPointer(t Type) *Pointer {
+       op, _ := optype(t).(*Pointer)
+       return op
+}
+
+func asTuple(t Type) *Tuple {
+       op, _ := optype(t).(*Tuple)
+       return op
+}
+
+func asSignature(t Type) *Signature {
+       op, _ := optype(t).(*Signature)
+       return op
+}
+
+func asSum(t Type) *Sum {
+       op, _ := optype(t).(*Sum)
+       return op
+}
+
+func asInterface(t Type) *Interface {
+       op, _ := optype(t).(*Interface)
+       return op
+}
+
+func asMap(t Type) *Map {
+       op, _ := optype(t).(*Map)
+       return op
+}
+
+func asChan(t Type) *Chan {
+       op, _ := optype(t).(*Chan)
+       return op
+}
+
+// If the argument to asNamed and asTypeParam is of the respective types
+// (possibly after expanding an instance type), these methods return that type.
+// Otherwise the result is nil.
+
+func asNamed(t Type) *Named {
+       e, _ := expand(t).(*Named)
+       return e
+}
+
+func asTypeParam(t Type) *TypeParam {
+       u, _ := under(t).(*TypeParam)
+       return u
+}
index 31c572f83b1234f8c48ad83a8d26513bce8343f0..64bbb3350545ed05ee2f9ab88687b6cf94dab4d3 100644 (file)
@@ -9,6 +9,7 @@ package types
 import (
        "bytes"
        "fmt"
+       "unicode/utf8"
 )
 
 // A Qualifier controls how named package-level objects are printed in
@@ -75,6 +76,10 @@ func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
        writeType(buf, typ, qf, make([]Type, 0, 8))
 }
 
+// instanceMarker is the prefix for an instantiated type
+// in "non-evaluated" instance form.
+const instanceMarker = '#'
+
 func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
        // Theoretically, this is a quadratic lookup algorithm, but in
        // practice deeply nested composite types with unnamed component
@@ -82,7 +87,7 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
        // using a map.
        for _, t := range visited {
                if t == typ {
-                       fmt.Fprintf(buf, "○%T", typ) // cycle to typ
+                       fmt.Fprintf(buf, "○%T", goTypeName(typ)) // cycle to typ
                        return
                }
        }
@@ -121,11 +126,19 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
                        if i > 0 {
                                buf.WriteString("; ")
                        }
-                       if !f.embedded {
-                               buf.WriteString(f.name)
+                       buf.WriteString(f.name)
+                       if f.embedded {
+                               // emphasize that the embedded field's name
+                               // doesn't match the field's type name
+                               if f.name != embeddedFieldName(f.typ) {
+                                       buf.WriteString(" /* = ")
+                                       writeType(buf, f.typ, qf, visited)
+                                       buf.WriteString(" */")
+                               }
+                       } else {
                                buf.WriteByte(' ')
+                               writeType(buf, f.typ, qf, visited)
                        }
-                       writeType(buf, f.typ, qf, visited)
                        if tag := t.Tag(i); tag != "" {
                                fmt.Fprintf(buf, " %q", tag)
                        }
@@ -143,6 +156,14 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
                buf.WriteString("func")
                writeSignature(buf, t, qf, visited)
 
+       case *Sum:
+               for i, t := range t.types {
+                       if i > 0 {
+                               buf.WriteString(", ")
+                       }
+                       writeType(buf, t, qf, visited)
+               }
+
        case *Interface:
                // We write the source-level methods and embedded types rather
                // than the actual method set since resolved method signatures
@@ -168,6 +189,13 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
                                writeSignature(buf, m.typ.(*Signature), qf, visited)
                                empty = false
                        }
+                       if !empty && t.allTypes != nil {
+                               buf.WriteString("; ")
+                       }
+                       if t.allTypes != nil {
+                               buf.WriteString("type ")
+                               writeType(buf, t.allTypes, qf, visited)
+                       }
                } else {
                        // print explicit interface methods and embedded types
                        for i, m := range t.methods {
@@ -178,8 +206,19 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
                                writeSignature(buf, m.typ.(*Signature), qf, visited)
                                empty = false
                        }
+                       if !empty && t.types != nil {
+                               buf.WriteString("; ")
+                       }
+                       if t.types != nil {
+                               buf.WriteString("type ")
+                               writeType(buf, t.types, qf, visited)
+                               empty = false
+                       }
+                       if !empty && len(t.embeddeds) > 0 {
+                               buf.WriteString("; ")
+                       }
                        for i, typ := range t.embeddeds {
-                               if i > 0 || len(t.methods) > 0 {
+                               if i > 0 {
                                        buf.WriteString("; ")
                                }
                                writeType(buf, typ, qf, visited)
@@ -227,17 +266,36 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
                }
 
        case *Named:
-               s := "<Named w/o object>"
-               if obj := t.obj; obj != nil {
-                       if obj.pkg != nil {
-                               writePackage(buf, obj.pkg, qf)
-                       }
-                       // TODO(gri): function-local named types should be displayed
-                       // differently from named types at package level to avoid
-                       // ambiguity.
-                       s = obj.name
+               writeTypeName(buf, t.obj, qf)
+               if t.targs != nil {
+                       // instantiated type
+                       buf.WriteByte('[')
+                       writeTypeList(buf, t.targs, qf, visited)
+                       buf.WriteByte(']')
+               } else if t.tparams != nil {
+                       // parameterized type
+                       writeTParamList(buf, t.tparams, qf, visited)
                }
-               buf.WriteString(s)
+
+       case *TypeParam:
+               s := "?"
+               if t.obj != nil {
+                       s = t.obj.name
+               }
+               buf.WriteString(s + subscript(t.id))
+
+       case *instance:
+               buf.WriteByte(instanceMarker) // indicate "non-evaluated" syntactic instance
+               writeTypeName(buf, t.base.obj, qf)
+               buf.WriteByte('[')
+               writeTypeList(buf, t.targs, qf, visited)
+               buf.WriteByte(']')
+
+       case *bottom:
+               buf.WriteString("⊥")
+
+       case *top:
+               buf.WriteString("⊤")
 
        default:
                // For externally defined implementations of Type.
@@ -245,6 +303,62 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
        }
 }
 
+func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
+       for i, typ := range list {
+               if i > 0 {
+                       buf.WriteString(", ")
+               }
+               writeType(buf, typ, qf, visited)
+       }
+}
+
+func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
+       // TODO(rFindley) compare this with the corresponding implementation in types2
+       buf.WriteString("[")
+       var prev Type
+       for i, p := range list {
+               // TODO(rFindley) support 'any' sugar here.
+               var b Type = &emptyInterface
+               if t, _ := p.typ.(*TypeParam); t != nil && t.bound != nil {
+                       b = t.bound
+               }
+               if i > 0 {
+                       if b != prev {
+                               // type bound changed - write previous one before advancing
+                               buf.WriteByte(' ')
+                               writeType(buf, prev, qf, visited)
+                       }
+                       buf.WriteString(", ")
+               }
+               prev = b
+
+               if t, _ := p.typ.(*TypeParam); t != nil {
+                       writeType(buf, t, qf, visited)
+               } else {
+                       buf.WriteString(p.name)
+               }
+       }
+       if prev != nil {
+               buf.WriteByte(' ')
+               writeType(buf, prev, qf, visited)
+       }
+       buf.WriteByte(']')
+}
+
+func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
+       s := "<Named w/o object>"
+       if obj != nil {
+               if obj.pkg != nil {
+                       writePackage(buf, obj.pkg, qf)
+               }
+               // TODO(gri): function-local named types should be displayed
+               // differently from named types at package level to avoid
+               // ambiguity.
+               s = obj.name
+       }
+       buf.WriteString(s)
+}
+
 func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
        buf.WriteByte('(')
        if tup != nil {
@@ -264,7 +378,7 @@ func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visi
                                } else {
                                        // special case:
                                        // append(s, "foo"...) leads to signature func([]byte, string...)
-                                       if t, ok := typ.Underlying().(*Basic); !ok || t.kind != String {
+                                       if t := asBasic(typ); t == nil || t.kind != String {
                                                panic("internal error: string type expected")
                                        }
                                        writeType(buf, typ, qf, visited)
@@ -287,6 +401,10 @@ func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
 }
 
 func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
+       if sig.tparams != nil {
+               writeTParamList(buf, sig.tparams, qf, visited)
+       }
+
        writeTuple(buf, sig.params, sig.variadic, qf, visited)
 
        n := sig.results.Len()
@@ -305,3 +423,38 @@ func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []T
        // multiple or named result(s)
        writeTuple(buf, sig.results, false, qf, visited)
 }
+
+// embeddedFieldName returns an embedded field's name given its type.
+// The result is "" if the type doesn't have an embedded field name.
+func embeddedFieldName(typ Type) string {
+       switch t := typ.(type) {
+       case *Basic:
+               return t.name
+       case *Named:
+               return t.obj.name
+       case *Pointer:
+               // *T is ok, but **T is not
+               if _, ok := t.base.(*Pointer); !ok {
+                       return embeddedFieldName(t.base)
+               }
+       case *instance:
+               return t.base.obj.name
+       }
+       return "" // not a (pointer to) a defined type
+}
+
+// subscript returns the decimal (utf8) representation of x using subscript digits.
+func subscript(x uint64) string {
+       const w = len("₀") // all digits 0...9 have the same utf8 width
+       var buf [32 * w]byte
+       i := len(buf)
+       for {
+               i -= w
+               utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
+               x /= 10
+               if x == 0 {
+                       break
+               }
+       }
+       return string(buf[i:])
+}
index 5d9db39bfc0e01535d55fd29976fb1d1fdfcc952..b16529dc64155cc306d1233d30b5d3d921dbf764 100644 (file)
@@ -96,6 +96,10 @@ var independentTestTypes = []testEntry{
        dup("interface{m()}"),
        dup(`interface{String() string; m(int) float32}`),
 
+       // TODO(rFindley) uncomment this once this AST is accepted, and add more test
+       // cases.
+       // dup(`interface{type int, float32, complex128}`),
+
        // maps
        dup("map[string]int"),
        {"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},
index 2b398010f4d0483f231c9c01b0862b2fbdcf5732..24df33965dab87642312bd17b8f05738573d4ac3 100644 (file)
@@ -7,11 +7,13 @@
 package types
 
 import (
+       "fmt"
        "go/ast"
        "go/constant"
        "go/token"
        "sort"
        "strconv"
+       "strings"
 )
 
 // ident type-checks identifier e and initializes x with the value or type of e.
@@ -120,6 +122,45 @@ func (check *Checker) typ(e ast.Expr) Type {
        return check.definedType(e, nil)
 }
 
+// varType type-checks the type expression e and returns its type, or Typ[Invalid].
+// The type must not be an (uninstantiated) generic type and it must be ordinary
+// (see ordinaryType).
+func (check *Checker) varType(e ast.Expr) Type {
+       typ := check.definedType(e, nil)
+       check.ordinaryType(e, typ)
+       return typ
+}
+
+// ordinaryType reports an error if typ is an interface type containing
+// type lists or is (or embeds) the predeclared type comparable.
+func (check *Checker) ordinaryType(pos positioner, typ Type) {
+       // We don't want to call under() (via asInterface) or complete interfaces
+       // while we are in the middle of type-checking parameter declarations that
+       // might belong to interface methods. Delay this check to the end of
+       // type-checking.
+       check.atEnd(func() {
+               if t := asInterface(typ); t != nil {
+                       check.completeInterface(pos.Pos(), t) // TODO(gri) is this the correct position?
+                       if t.allTypes != nil {
+                               check.softErrorf(pos, 0, "interface contains type constraints (%s)", t.allTypes)
+                               return
+                       }
+                       if t.IsComparable() {
+                               check.softErrorf(pos, 0, "interface is (or embeds) comparable")
+                       }
+               }
+       })
+}
+
+// anyType type-checks the type expression e and returns its type, or Typ[Invalid].
+// The type may be generic or instantiated.
+func (check *Checker) anyType(e ast.Expr) Type {
+       typ := check.typInternal(e, nil)
+       assert(isTyped(typ))
+       check.recordTypeAndValue(e, typexpr, typ, nil)
+       return typ
+}
+
 // definedType is like typ but also accepts a type name def.
 // If def != nil, e is the type specification for the defined type def, declared
 // in a type declaration, and def.underlying will be set to the type of e before
@@ -159,7 +200,9 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
                var recv *Var
                switch len(recvList) {
                case 0:
-                       check.error(recvPar, _BadRecv, "method is missing receiver")
+                       // TODO(rFindley) this is now redundant with resolver.go. Clean up when
+                       //                importing remaining typexpr.go changes.
+                       // check.error(recvPar, _BadRecv, "method is missing receiver")
                        recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below
                default:
                        // more than one receiver
@@ -207,6 +250,12 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
        sig.variadic = variadic
 }
 
+// goTypeName returns the Go type name for typ and
+// removes any occurences of "types." from that name.
+func goTypeName(typ Type) string {
+       return strings.ReplaceAll(fmt.Sprintf("%T", typ), "types.", "")
+}
+
 // typInternal drives type checking of types.
 // Must only be called by definedType.
 //
@@ -498,7 +547,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
                        // it if it's a valid interface.
                        typ := check.typ(f.Type)
 
-                       utyp := check.underlying(typ)
+                       utyp := under(typ)
                        if _, ok := utyp.(*Interface); !ok {
                                if utyp != Typ[Invalid] {
                                        check.errorf(f.Type, _InvalidIfaceEmbed, "%s is not an interface", typ)
@@ -521,10 +570,10 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
        sort.Sort(byUniqueMethodName(ityp.methods))
        sort.Stable(byUniqueTypeName(ityp.embeddeds))
 
-       check.later(func() { check.completeInterface(ityp) })
+       check.later(func() { check.completeInterface(iface.Pos(), ityp) })
 }
 
-func (check *Checker) completeInterface(ityp *Interface) {
+func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) {
        if ityp.allMethods != nil {
                return
        }
@@ -538,11 +587,18 @@ func (check *Checker) completeInterface(ityp *Interface) {
        }
 
        if trace {
-               check.trace(token.NoPos, "complete %s", ityp)
+               // Types don't generally have position information.
+               // If we don't have a valid pos provided, try to use
+               // one close enough.
+               if !pos.IsValid() && len(ityp.methods) > 0 {
+                       pos = ityp.methods[0].pos
+               }
+
+               check.trace(pos, "complete %s", ityp)
                check.indent++
                defer func() {
                        check.indent--
-                       check.trace(token.NoPos, "=> %s", ityp)
+                       check.trace(pos, "=> %s (methods = %v, types = %v)", ityp, ityp.allMethods, ityp.allTypes)
                }()
        }
 
@@ -592,25 +648,77 @@ func (check *Checker) completeInterface(ityp *Interface) {
                addMethod(m.pos, m, true)
        }
 
+       // collect types
+       allTypes := ityp.types
+
        posList := check.posMap[ityp]
        for i, typ := range ityp.embeddeds {
                pos := posList[i] // embedding position
-               typ, ok := check.underlying(typ).(*Interface)
-               if !ok {
-                       // An error was reported when collecting the embedded types.
-                       // Ignore it.
+               utyp := under(typ)
+               etyp := asInterface(utyp)
+               if etyp == nil {
+                       if utyp != Typ[Invalid] {
+                               var format string
+                               if _, ok := utyp.(*TypeParam); ok {
+                                       format = "%s is a type parameter, not an interface"
+                               } else {
+                                       format = "%s is not an interface"
+                               }
+                               // TODO: correct error code.
+                               check.errorf(atPos(pos), 0, format, typ)
+                       }
                        continue
                }
-               check.completeInterface(typ)
-               for _, m := range typ.allMethods {
+               check.completeInterface(pos, etyp)
+               for _, m := range etyp.allMethods {
                        addMethod(pos, m, false) // use embedding position pos rather than m.pos
                }
+               allTypes = intersect(allTypes, etyp.allTypes)
        }
 
        if methods != nil {
                sort.Sort(byUniqueMethodName(methods))
                ityp.allMethods = methods
        }
+       ityp.allTypes = allTypes
+}
+
+// intersect computes the intersection of the types x and y.
+// Note: A incomming nil type stands for the top type. A top
+// type result is returned as nil.
+func intersect(x, y Type) (r Type) {
+       defer func() {
+               if r == theTop {
+                       r = nil
+               }
+       }()
+
+       switch {
+       case x == theBottom || y == theBottom:
+               return theBottom
+       case x == nil || x == theTop:
+               return y
+       case y == nil || x == theTop:
+               return x
+       }
+
+       xtypes := unpackType(x)
+       ytypes := unpackType(y)
+       // Compute the list rtypes which includes only
+       // types that are in both xtypes and ytypes.
+       // Quadratic algorithm, but good enough for now.
+       // TODO(gri) fix this
+       var rtypes []Type
+       for _, x := range xtypes {
+               if includes(ytypes, x) {
+                       rtypes = append(rtypes, x)
+               }
+       }
+
+       if rtypes == nil {
+               return theBottom
+       }
+       return NewSum(rtypes)
 }
 
 // byUniqueTypeName named type lists can be sorted by their unique type names.
@@ -762,3 +870,13 @@ func embeddedFieldIdent(e ast.Expr) *ast.Ident {
        }
        return nil // invalid embedded field
 }
+
+// includes reports whether typ is in list.
+func includes(list []Type, typ Type) bool {
+       for _, e := range list {
+               if Identical(typ, e) {
+                       return true
+               }
+       }
+       return false
+}
diff --git a/src/go/types/unify.go b/src/go/types/unify.go
new file mode 100644 (file)
index 0000000..ab18feb
--- /dev/null
@@ -0,0 +1,452 @@
+// Copyright 2020 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.
+
+// This file implements type unification.
+
+package types
+
+import (
+       "go/token"
+       "sort"
+)
+
+// The unifier maintains two separate sets of type parameters x and y
+// which are used to resolve type parameters in the x and y arguments
+// provided to the unify call. For unidirectional unification, only
+// one of these sets (say x) is provided, and then type parameters are
+// only resolved for the x argument passed to unify, not the y argument
+// (even if that also contains possibly the same type parameters). This
+// is crucial to infer the type parameters of self-recursive calls:
+//
+//     func f[P any](a P) { f(a) }
+//
+// For the call f(a) we want to infer that the type argument for P is P.
+// During unification, the parameter type P must be resolved to the type
+// parameter P ("x" side), but the argument type P must be left alone so
+// that unification resolves the type parameter P to P.
+//
+// For bidirection unification, both sets are provided. This enables
+// unification to go from argument to parameter type and vice versa.
+// For constraint type inference, we use bidirectional unification
+// where both the x and y type parameters are identical. This is done
+// by setting up one of them (using init) and then assigning its value
+// to the other.
+
+// A unifier maintains the current type parameters for x and y
+// and the respective types inferred for each type parameter.
+// A unifier is created by calling newUnifier.
+type unifier struct {
+       check *Checker
+       exact bool
+       x, y  tparamsList // x and y must initialized via tparamsList.init
+       types []Type      // inferred types, shared by x and y
+}
+
+// newUnifier returns a new unifier.
+// If exact is set, unification requires unified types to match
+// exactly. If exact is not set, a named type's underlying type
+// is considered if unification would fail otherwise, and the
+// direction of channels is ignored.
+func newUnifier(check *Checker, exact bool) *unifier {
+       u := &unifier{check: check, exact: exact}
+       u.x.unifier = u
+       u.y.unifier = u
+       return u
+}
+
+// unify attempts to unify x and y and reports whether it succeeded.
+func (u *unifier) unify(x, y Type) bool {
+       return u.nify(x, y, nil)
+}
+
+// A tparamsList describes a list of type parameters and the types inferred for them.
+type tparamsList struct {
+       unifier *unifier
+       tparams []*TypeName
+       // For each tparams element, there is a corresponding type slot index in indices.
+       // index  < 0: unifier.types[-index-1] == nil
+       // index == 0: no type slot allocated yet
+       // index  > 0: unifier.types[index-1] == typ
+       // Joined tparams elements share the same type slot and thus have the same index.
+       // By using a negative index for nil types we don't need to check unifier.types
+       // to see if we have a type or not.
+       indices []int // len(d.indices) == len(d.tparams)
+}
+
+// init initializes d with the given type parameters.
+// The type parameters must be in the order in which they appear in their declaration
+// (this ensures that the tparams indices match the respective type parameter index).
+func (d *tparamsList) init(tparams []*TypeName) {
+       if len(tparams) == 0 {
+               return
+       }
+       if debug {
+               for i, tpar := range tparams {
+                       assert(i == tpar.typ.(*TypeParam).index)
+               }
+       }
+       d.tparams = tparams
+       d.indices = make([]int, len(tparams))
+}
+
+// join unifies the i'th type parameter of x with the j'th type parameter of y.
+// If both type parameters already have a type associated with them and they are
+// not joined, join fails and return false.
+func (u *unifier) join(i, j int) bool {
+       ti := u.x.indices[i]
+       tj := u.y.indices[j]
+       switch {
+       case ti == 0 && tj == 0:
+               // Neither type parameter has a type slot associated with them.
+               // Allocate a new joined nil type slot (negative index).
+               u.types = append(u.types, nil)
+               u.x.indices[i] = -len(u.types)
+               u.y.indices[j] = -len(u.types)
+       case ti == 0:
+               // The type parameter for x has no type slot yet. Use slot of y.
+               u.x.indices[i] = tj
+       case tj == 0:
+               // The type parameter for y has no type slot yet. Use slot of x.
+               u.y.indices[j] = ti
+
+       // Both type parameters have a slot: ti != 0 && tj != 0.
+       case ti == tj:
+               // Both type parameters already share the same slot. Nothing to do.
+               break
+       case ti > 0 && tj > 0:
+               // Both type parameters have (possibly different) inferred types. Cannot join.
+               return false
+       case ti > 0:
+               // Only the type parameter for x has an inferred type. Use x slot for y.
+               u.y.setIndex(j, ti)
+       default:
+               // Either the type parameter for y has an inferred type, or neither type
+               // parameter has an inferred type. In either case, use y slot for x.
+               u.x.setIndex(i, tj)
+       }
+       return true
+}
+
+// If typ is a type parameter of d, index returns the type parameter index.
+// Otherwise, the result is < 0.
+func (d *tparamsList) index(typ Type) int {
+       if t, ok := typ.(*TypeParam); ok {
+               if i := t.index; i < len(d.tparams) && d.tparams[i].typ == t {
+                       return i
+               }
+       }
+       return -1
+}
+
+// setIndex sets the type slot index for the i'th type parameter
+// (and all its joined parameters) to tj. The type parameter
+// must have a (possibly nil) type slot associated with it.
+func (d *tparamsList) setIndex(i, tj int) {
+       ti := d.indices[i]
+       assert(ti != 0 && tj != 0)
+       for k, tk := range d.indices {
+               if tk == ti {
+                       d.indices[k] = tj
+               }
+       }
+}
+
+// at returns the type set for the i'th type parameter; or nil.
+func (d *tparamsList) at(i int) Type {
+       if ti := d.indices[i]; ti > 0 {
+               return d.unifier.types[ti-1]
+       }
+       return nil
+}
+
+// set sets the type typ for the i'th type parameter;
+// typ must not be nil and it must not have been set before.
+func (d *tparamsList) set(i int, typ Type) {
+       assert(typ != nil)
+       u := d.unifier
+       switch ti := d.indices[i]; {
+       case ti < 0:
+               u.types[-ti-1] = typ
+               d.setIndex(i, -ti)
+       case ti == 0:
+               u.types = append(u.types, typ)
+               d.indices[i] = len(u.types)
+       default:
+               panic("type already set")
+       }
+}
+
+// types returns the list of inferred types (via unification) for the type parameters
+// described by d, and an index. If all types were inferred, the returned index is < 0.
+// Otherwise, it is the index of the first type parameter which couldn't be inferred;
+// i.e., for which list[index] is nil.
+func (d *tparamsList) types() (list []Type, index int) {
+       list = make([]Type, len(d.tparams))
+       index = -1
+       for i := range d.tparams {
+               t := d.at(i)
+               list[i] = t
+               if index < 0 && t == nil {
+                       index = i
+               }
+       }
+       return
+}
+
+func (u *unifier) nifyEq(x, y Type, p *ifacePair) bool {
+       return x == y || u.nify(x, y, p)
+}
+
+// nify implements the core unification algorithm which is an
+// adapted version of Checker.identical0. For changes to that
+// code the corresponding changes should be made here.
+// Must not be called directly from outside the unifier.
+func (u *unifier) nify(x, y Type, p *ifacePair) bool {
+       // types must be expanded for comparison
+       x = expand(x)
+       y = expand(y)
+
+       if !u.exact {
+               // If exact unification is known to fail because we attempt to
+               // match a type name against an unnamed type literal, consider
+               // the underlying type of the named type.
+               // (Subtle: We use isNamed to include any type with a name (incl.
+               // basic types and type parameters. We use asNamed() because we only
+               // want *Named types.)
+               switch {
+               case !isNamed(x) && y != nil && asNamed(y) != nil:
+                       return u.nify(x, under(y), p)
+               case x != nil && asNamed(x) != nil && !isNamed(y):
+                       return u.nify(under(x), y, p)
+               }
+       }
+
+       // Cases where at least one of x or y is a type parameter.
+       switch i, j := u.x.index(x), u.y.index(y); {
+       case i >= 0 && j >= 0:
+               // both x and y are type parameters
+               if u.join(i, j) {
+                       return true
+               }
+               // both x and y have an inferred type - they must match
+               return u.nifyEq(u.x.at(i), u.y.at(j), p)
+
+       case i >= 0:
+               // x is a type parameter, y is not
+               if tx := u.x.at(i); tx != nil {
+                       return u.nifyEq(tx, y, p)
+               }
+               // otherwise, infer type from y
+               u.x.set(i, y)
+               return true
+
+       case j >= 0:
+               // y is a type parameter, x is not
+               if ty := u.y.at(j); ty != nil {
+                       return u.nifyEq(x, ty, p)
+               }
+               // otherwise, infer type from x
+               u.y.set(j, x)
+               return true
+       }
+
+       // For type unification, do not shortcut (x == y) for identical
+       // types. Instead keep comparing them element-wise to unify the
+       // matching (and equal type parameter types). A simple test case
+       // where this matters is: func f[P any](a P) { f(a) } .
+
+       switch x := x.(type) {
+       case *Basic:
+               // Basic types are singletons except for the rune and byte
+               // aliases, thus we cannot solely rely on the x == y check
+               // above. See also comment in TypeName.IsAlias.
+               if y, ok := y.(*Basic); ok {
+                       return x.kind == y.kind
+               }
+
+       case *Array:
+               // Two array types are identical if they have identical element types
+               // and the same array length.
+               if y, ok := y.(*Array); ok {
+                       // If one or both array lengths are unknown (< 0) due to some error,
+                       // assume they are the same to avoid spurious follow-on errors.
+                       return (x.len < 0 || y.len < 0 || x.len == y.len) && u.nify(x.elem, y.elem, p)
+               }
+
+       case *Slice:
+               // Two slice types are identical if they have identical element types.
+               if y, ok := y.(*Slice); ok {
+                       return u.nify(x.elem, y.elem, p)
+               }
+
+       case *Struct:
+               // Two struct types are identical if they have the same sequence of fields,
+               // and if corresponding fields have the same names, and identical types,
+               // and identical tags. Two embedded fields are considered to have the same
+               // name. Lower-case field names from different packages are always different.
+               if y, ok := y.(*Struct); ok {
+                       if x.NumFields() == y.NumFields() {
+                               for i, f := range x.fields {
+                                       g := y.fields[i]
+                                       if f.embedded != g.embedded ||
+                                               x.Tag(i) != y.Tag(i) ||
+                                               !f.sameId(g.pkg, g.name) ||
+                                               !u.nify(f.typ, g.typ, p) {
+                                               return false
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *Pointer:
+               // Two pointer types are identical if they have identical base types.
+               if y, ok := y.(*Pointer); ok {
+                       return u.nify(x.base, y.base, p)
+               }
+
+       case *Tuple:
+               // Two tuples types are identical if they have the same number of elements
+               // and corresponding elements have identical types.
+               if y, ok := y.(*Tuple); ok {
+                       if x.Len() == y.Len() {
+                               if x != nil {
+                                       for i, v := range x.vars {
+                                               w := y.vars[i]
+                                               if !u.nify(v.typ, w.typ, p) {
+                                                       return false
+                                               }
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *Signature:
+               // Two function types are identical if they have the same number of parameters
+               // and result values, corresponding parameter and result types are identical,
+               // and either both functions are variadic or neither is. Parameter and result
+               // names are not required to match.
+               // TODO(gri) handle type parameters or document why we can ignore them.
+               if y, ok := y.(*Signature); ok {
+                       return x.variadic == y.variadic &&
+                               u.nify(x.params, y.params, p) &&
+                               u.nify(x.results, y.results, p)
+               }
+
+       case *Sum:
+               // This should not happen with the current internal use of sum types.
+               panic("type inference across sum types not implemented")
+
+       case *Interface:
+               // Two interface types are identical if they have the same set of methods with
+               // the same names and identical function types. Lower-case method names from
+               // different packages are always different. The order of the methods is irrelevant.
+               if y, ok := y.(*Interface); ok {
+                       // If identical0 is called (indirectly) via an external API entry point
+                       // (such as Identical, IdenticalIgnoreTags, etc.), check is nil. But in
+                       // that case, interfaces are expected to be complete and lazy completion
+                       // here is not needed.
+                       if u.check != nil {
+                               u.check.completeInterface(token.NoPos, x)
+                               u.check.completeInterface(token.NoPos, y)
+                       }
+                       a := x.allMethods
+                       b := y.allMethods
+                       if len(a) == len(b) {
+                               // Interface types are the only types where cycles can occur
+                               // that are not "terminated" via named types; and such cycles
+                               // can only be created via method parameter types that are
+                               // anonymous interfaces (directly or indirectly) embedding
+                               // the current interface. Example:
+                               //
+                               //    type T interface {
+                               //        m() interface{T}
+                               //    }
+                               //
+                               // If two such (differently named) interfaces are compared,
+                               // endless recursion occurs if the cycle is not detected.
+                               //
+                               // If x and y were compared before, they must be equal
+                               // (if they were not, the recursion would have stopped);
+                               // search the ifacePair stack for the same pair.
+                               //
+                               // This is a quadratic algorithm, but in practice these stacks
+                               // are extremely short (bounded by the nesting depth of interface
+                               // type declarations that recur via parameter types, an extremely
+                               // rare occurrence). An alternative implementation might use a
+                               // "visited" map, but that is probably less efficient overall.
+                               q := &ifacePair{x, y, p}
+                               for p != nil {
+                                       if p.identical(q) {
+                                               return true // same pair was compared before
+                                       }
+                                       p = p.prev
+                               }
+                               if debug {
+                                       assert(sort.IsSorted(byUniqueMethodName(a)))
+                                       assert(sort.IsSorted(byUniqueMethodName(b)))
+                               }
+                               for i, f := range a {
+                                       g := b[i]
+                                       if f.Id() != g.Id() || !u.nify(f.typ, g.typ, q) {
+                                               return false
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *Map:
+               // Two map types are identical if they have identical key and value types.
+               if y, ok := y.(*Map); ok {
+                       return u.nify(x.key, y.key, p) && u.nify(x.elem, y.elem, p)
+               }
+
+       case *Chan:
+               // Two channel types are identical if they have identical value types.
+               if y, ok := y.(*Chan); ok {
+                       return (!u.exact || x.dir == y.dir) && u.nify(x.elem, y.elem, p)
+               }
+
+       case *Named:
+               // Two named types are identical if their type names originate
+               // in the same type declaration.
+               // if y, ok := y.(*Named); ok {
+               //      return x.obj == y.obj
+               // }
+               if y, ok := y.(*Named); ok {
+                       // TODO(gri) This is not always correct: two types may have the same names
+                       //           in the same package if one of them is nested in a function.
+                       //           Extremely unlikely but we need an always correct solution.
+                       if x.obj.pkg == y.obj.pkg && x.obj.name == y.obj.name {
+                               assert(len(x.targs) == len(y.targs))
+                               for i, x := range x.targs {
+                                       if !u.nify(x, y.targs[i], p) {
+                                               return false
+                                       }
+                               }
+                               return true
+                       }
+               }
+
+       case *TypeParam:
+               // Two type parameters (which are not part of the type parameters of the
+               // enclosing type as those are handled in the beginning of this function)
+               // are identical if they originate in the same declaration.
+               return x == y
+
+       // case *instance:
+       //      unreachable since types are expanded
+
+       case nil:
+               // avoid a crash in case of nil type
+
+       default:
+               u.check.dump("### u.nify(%s, %s), u.x.tparams = %s", x, y, u.x.tparams)
+               unreachable()
+       }
+
+       return false
+}
index ff5b89118ad9ef940ae1fbe1e00276190e6f0476..f2f444fd9d1dd9320f81990d1d73a1165122577f 100644 (file)
@@ -24,6 +24,7 @@ var (
        universeIota  *Const
        universeByte  *Basic // uint8 alias, but has name "byte"
        universeRune  *Basic // int32 alias, but has name "rune"
+       universeAny   *Named
        universeError *Named
 )
 
@@ -77,13 +78,24 @@ func defPredeclaredTypes() {
                def(NewTypeName(token.NoPos, nil, t.name, t))
        }
 
+       // any
+       // (Predeclared and entered into universe scope so we do all the
+       // usual checks; but removed again from scope later since it's
+       // only visible as constraint in a type parameter list.)
+       {
+               typ := &Named{underlying: &emptyInterface}
+               def(NewTypeName(token.NoPos, nil, "any", typ))
+       }
+
        // Error has a nil package in its qualified name since it is in no package
-       res := NewVar(token.NoPos, nil, "", Typ[String])
-       sig := &Signature{results: NewTuple(res)}
-       err := NewFunc(token.NoPos, nil, "Error", sig)
-       typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil).Complete()}
-       sig.recv = NewVar(token.NoPos, nil, "", typ)
-       def(NewTypeName(token.NoPos, nil, "error", typ))
+       {
+               res := NewVar(token.NoPos, nil, "", Typ[String])
+               sig := &Signature{results: NewTuple(res)}
+               err := NewFunc(token.NoPos, nil, "Error", sig)
+               typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil).Complete()}
+               sig.recv = NewVar(token.NoPos, nil, "", typ)
+               def(NewTypeName(token.NoPos, nil, "error", typ))
+       }
 }
 
 var predeclaredConsts = [...]struct {
@@ -188,6 +200,33 @@ func DefPredeclaredTestFuncs() {
        def(newBuiltin(_Trace))
 }
 
+func defPredeclaredComparable() {
+       // The "comparable" interface can be imagined as defined like
+       //
+       // type comparable interface {
+       //         == () untyped bool
+       //         != () untyped bool
+       // }
+       //
+       // == and != cannot be user-declared but we can declare
+       // a magic method == and check for its presence when needed.
+
+       // Define interface { == () }. We don't care about the signature
+       // for == so leave it empty except for the receiver, which is
+       // set up later to match the usual interface method assumptions.
+       sig := new(Signature)
+       eql := NewFunc(token.NoPos, nil, "==", sig)
+       iface := NewInterfaceType([]*Func{eql}, nil).Complete()
+
+       // set up the defined type for the interface
+       obj := NewTypeName(token.NoPos, nil, "comparable", nil)
+       named := NewNamed(obj, iface, nil)
+       obj.color_ = black
+       sig.recv = NewVar(token.NoPos, nil, "", named) // complete == signature
+
+       def(obj)
+}
+
 func init() {
        Universe = NewScope(nil, token.NoPos, token.NoPos, "universe")
        Unsafe = NewPackage("unsafe", "unsafe")
@@ -197,11 +236,16 @@ func init() {
        defPredeclaredConsts()
        defPredeclaredNil()
        defPredeclaredFuncs()
+       defPredeclaredComparable()
 
        universeIota = Universe.Lookup("iota").(*Const)
        universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic)
        universeRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic)
+       universeAny = Universe.Lookup("any").(*TypeName).typ.(*Named)
        universeError = Universe.Lookup("error").(*TypeName).typ.(*Named)
+
+       // "any" is only visible as constraint in a type parameter list
+       delete(Universe.elems, "any")
 }
 
 // Objects with names containing blanks are internal and not entered into
@@ -215,7 +259,7 @@ func def(obj Object) {
                return // nothing to do
        }
        // fix Obj link for named types
-       if typ, ok := obj.Type().(*Named); ok {
+       if typ := asNamed(obj.Type()); typ != nil {
                typ.obj = obj.(*TypeName)
        }
        // exported identifiers go into package unsafe
index 1c141ac490c7fe9138fb6ff982e50b4f7a4e3acb..d7b5dccb68c2c9bb4b048a4f33643e955ff65e9b 100644 (file)
@@ -36,7 +36,7 @@ type (
 
 // Methods can be declared on the original named type and the alias.
 func (T0) m1()  {} // GCCGO_ERROR "previous"
-func (*T0) m1() {} // ERROR "method redeclared: T0\.m1|redefinition of .m1."
+func (*T0) m1() {} // ERROR "method redeclared: T0\.m1|T0\.m1 redeclared in this block|redefinition of .m1."
 func (A0) m1()  {} // ERROR "T0\.m1 redeclared in this block|redefinition of .m1."
 func (A0) m1()  {} // ERROR "T0\.m1 redeclared in this block|redefinition of .m1."
 func (A0) m2()  {}
@@ -90,7 +90,7 @@ func _() {
 
 // Invalid type alias declarations.
 
-type _ = reflect.ValueOf // ERROR "reflect.ValueOf is not a type|expected type"
+type _ = reflect.ValueOf // ERROR "reflect.ValueOf .*is not a type|expected type"
 
 func (A1) m() {} // ERROR "cannot define new methods on non-local type int|may not define methods on non-local type"
 func (A2) m() {} // ERROR "invalid receiver type"
index 0fe24c09564df019b8bce6f705f8ea6cb6bbb4f8..9dab120b25b19780e098ba8700d7cbcb1323a450 100644 (file)
@@ -13,10 +13,10 @@ func main() {
 
        s := make([]int, 8)
 
-       _ = append()           // ERROR "missing arguments to append"
-       _ = append(s...)       // ERROR "cannot use ... on first argument"
-       _ = append(s, 2, s...) // ERROR "too many arguments to append"
+       _ = append()           // ERROR "missing arguments to append|not enough arguments for append"
+       _ = append(s...)       // ERROR "cannot use ... on first argument|not enough arguments in call to append"
+       _ = append(s, 2, s...) // ERROR "too many arguments to append|too many arguments in call to append"
 
-       _ = append(s, make([]int, 0))     // ERROR "cannot use make.* as type int in append"
-       _ = append(s, make([]int, -1)...) // ERROR "negative len argument in make"
+       _ = append(s, make([]int, 0))     // ERROR "cannot use make.* as type int in append|cannot use make.* as int value"
+       _ = append(s, make([]int, -1)...) // ERROR "negative len argument in make|index -1.* must not be negative"
 }
index 62fd3b5be3ca2923d41bba0714f41d838004ceab..bdec58b710f4210a7741a6973a5cd4ed0ce64211 100644 (file)
@@ -56,13 +56,13 @@ func main() {
        {
                var x = 1
                {
-                       x, x := 2, 3 // ERROR ".*x.* repeated on left side of :="
+                       x, x := 2, 3 // ERROR ".*x.* repeated on left side of :=|x redeclared in this block"
                        _ = x
                }
                _ = x
        }
        {
-               a, a := 1, 2 // ERROR ".*a.* repeated on left side of :="
+               a, a := 1, 2 // ERROR ".*a.* repeated on left side of :=|a redeclared in this block"
                _ = a
        }
 }
index 70e01b1a307fd96409b0052794938ced33f866f6..815a7e9b5a8b5eda5314acaaf676207583fea9af 100644 (file)
@@ -25,8 +25,8 @@ func main() {
        _()     // ERROR "cannot use .* as value"
        x := _+1        // ERROR "cannot use .* as value"
        _ = x
-       _ = t._ // ERROR "cannot refer to blank field|invalid use of"
+       _ = t._ // ERROR "cannot refer to blank field|invalid use of|t._ undefined"
 
       var v1, v2 T
-      _ = v1 == v2 // ERROR "cannot be compared|non-comparable"
+      _ = v1 == v2 // ERROR "cannot be compared|non-comparable|cannot compare v1 == v2"
 }
index 0de04ecad06aeb6c2b0a7e624522246ddc92469d..27e62890c5249f6edd2d7e691af3d92f38daac40 100644 (file)
@@ -10,24 +10,24 @@ package main
 
 func main() {
        var s string = "hello"
-       s[1:2] = "a" // ERROR "cannot assign to .* \(strings are immutable\)"
-       s[3] = "b"   // ERROR "cannot assign to .* \(strings are immutable\)"
+       s[1:2] = "a" // ERROR "cannot assign to .* (\(strings are immutable\))?"
+       s[3] = "b"   // ERROR "cannot assign to .* (\(strings are immutable\))?"
 
        const n int = 1
        const cs string = "hello"
-       n = 2        // ERROR "cannot assign to .* \(declared const\)"
-       cs = "hi"    // ERROR "cannot assign to .* \(declared const\)"
-       true = false // ERROR "cannot assign to .* \(declared const\)"
+       n = 2        // ERROR "cannot assign to .* (\(declared const\))?"
+       cs = "hi"    // ERROR "cannot assign to .* (\(declared const\))?"
+       true = false // ERROR "cannot assign to .* (\(declared const\))?"
 
        var m map[int]struct{ n int }
        m[0].n = 7 // ERROR "cannot assign to struct field .* in map$"
 
-       1 = 7         // ERROR "cannot assign to 1$"
-       "hi" = 7      // ERROR `cannot assign to "hi"$`
-       nil = 7       // ERROR "cannot assign to nil$"
-       len("") = 7   // ERROR `cannot assign to len\(""\)$`
-       []int{} = nil // ERROR "cannot assign to \[\]int\{\}$"
+       1 = 7         // ERROR "cannot assign to 1"
+       "hi" = 7      // ERROR `cannot assign to "hi"`
+       nil = 7       // ERROR "cannot assign to nil"
+       len("") = 7   // ERROR `cannot assign to len\(""\)`
+       []int{} = nil // ERROR "cannot assign to \[\]int\{\}"
 
        var x int = 7
-       x + 1 = 7 // ERROR "cannot assign to x \+ 1$"
+       x + 1 = 7 // ERROR "cannot assign to x \+ 1"
 }
index 0c96d921d1ea303bb1d78240cf3ccf97d8b02e04..4c94ab7ffaeefb2e96cd260768e2a4ceb2486983 100644 (file)
@@ -66,5 +66,5 @@ func main() {
        close(c)
        close(cs)
        close(cr) // ERROR "receive"
-       close(n)  // ERROR "invalid operation.*non-chan type|must be channel"
+       close(n)  // ERROR "invalid operation.*non-chan type|must be channel|not a channel"
 }
index 7cf76044ef9b8ebc97baefeb00ccfa31a14fb9ef..704ead2caa89ffb6d8160be69fbce6a2c95ef538 100644 (file)
@@ -63,16 +63,16 @@ func main() {
        use(a3 == a3) // ERROR "invalid operation|invalid comparison"
 
        // Comparison of structs should have a good message
-       use(t3 == t3) // ERROR "struct|expected"
-       use(t4 == t4) // ERROR "cannot be compared|non-comparable"
+       use(t3 == t3) // ERROR "struct|expected|cannot compare"
+       use(t4 == t4) // ERROR "cannot be compared|non-comparable|cannot compare"
 
        // Slices, functions, and maps too.
        var x []int
        var f func()
        var m map[int]int
-       use(x == x) // ERROR "slice can only be compared to nil"
-       use(f == f) // ERROR "func can only be compared to nil"
-       use(m == m) // ERROR "map can only be compared to nil"
+       use(x == x) // ERROR "slice can only be compared to nil|cannot compare"
+       use(f == f) // ERROR "func can only be compared to nil|cannot compare"
+       use(m == m) // ERROR "map can only be compared to nil|cannot compare"
 
        // Comparison with interface that cannot return true
        // (would panic).
index 3fd5b55522fd5d849b24ce14de1815a9c2a93cc8..1efe688cb99ce2a4749ef083cca763b8e3ee09ad 100644 (file)
@@ -30,43 +30,43 @@ const (
 )
 
 var (
-       a1 = Int8 * 100              // ERROR "overflow"
+       a1 = Int8 * 100              // ERROR "overflow|cannot convert"
        a2 = Int8 * -1               // OK
-       a3 = Int8 * 1000             // ERROR "overflow"
-       a4 = Int8 * int8(1000)       // ERROR "overflow"
-       a5 = int8(Int8 * 1000)       // ERROR "overflow"
-       a6 = int8(Int8 * int8(1000)) // ERROR "overflow"
-       a7 = Int8 - 2*Int8 - 2*Int8  // ERROR "overflow"
-       a8 = Int8 * Const / 100      // ERROR "overflow"
+       a3 = Int8 * 1000             // ERROR "overflow|cannot convert"
+       a4 = Int8 * int8(1000)       // ERROR "overflow|cannot convert"
+       a5 = int8(Int8 * 1000)       // ERROR "overflow|cannot convert"
+       a6 = int8(Int8 * int8(1000)) // ERROR "overflow|cannot convert"
+       a7 = Int8 - 2*Int8 - 2*Int8  // ERROR "overflow|cannot convert"
+       a8 = Int8 * Const / 100      // ERROR "overflow|cannot convert"
        a9 = Int8 * (Const / 100)    // OK
 
-       b1        = Uint8 * Uint8         // ERROR "overflow"
-       b2        = Uint8 * -1            // ERROR "overflow"
+       b1        = Uint8 * Uint8         // ERROR "overflow|cannot convert"
+       b2        = Uint8 * -1            // ERROR "overflow|cannot convert"
        b3        = Uint8 - Uint8         // OK
-       b4        = Uint8 - Uint8 - Uint8 // ERROR "overflow"
-       b5        = uint8(^0)             // ERROR "overflow"
+       b4        = Uint8 - Uint8 - Uint8 // ERROR "overflow|cannot convert"
+       b5        = uint8(^0)             // ERROR "overflow|cannot convert"
        b5a       = int64(^0)             // OK
        b6        = ^uint8(0)             // OK
        b6a       = ^int64(0)             // OK
-       b7        = uint8(Minus1)         // ERROR "overflow"
-       b8        = uint8(int8(-1))       // ERROR "overflow"
-       b8a       = uint8(-1)             // ERROR "overflow"
+       b7        = uint8(Minus1)         // ERROR "overflow|cannot convert"
+       b8        = uint8(int8(-1))       // ERROR "overflow|cannot convert"
+       b8a       = uint8(-1)             // ERROR "overflow|cannot convert"
        b9   byte = (1 << 10) >> 8        // OK
-       b10  byte = (1 << 10)             // ERROR "overflow"
-       b11  byte = (byte(1) << 10) >> 8  // ERROR "overflow"
-       b12  byte = 1000                  // ERROR "overflow"
-       b13  byte = byte(1000)            // ERROR "overflow"
-       b14  byte = byte(100) * byte(100) // ERROR "overflow"
-       b15  byte = byte(100) * 100       // ERROR "overflow"
-       b16  byte = byte(0) * 1000        // ERROR "overflow"
+       b10  byte = (1 << 10)             // ERROR "overflow|cannot convert"
+       b11  byte = (byte(1) << 10) >> 8  // ERROR "overflow|cannot convert"
+       b12  byte = 1000                  // ERROR "overflow|cannot convert"
+       b13  byte = byte(1000)            // ERROR "overflow|cannot convert"
+       b14  byte = byte(100) * byte(100) // ERROR "overflow|cannot convert"
+       b15  byte = byte(100) * 100       // ERROR "overflow|cannot convert"
+       b16  byte = byte(0) * 1000        // ERROR "overflow|cannot convert"
        b16a byte = 0 * 1000              // OK
-       b17  byte = byte(0) * byte(1000)  // ERROR "overflow"
+       b17  byte = byte(0) * byte(1000)  // ERROR "overflow|cannot convert"
        b18  byte = Uint8 / 0             // ERROR "division by zero"
 
        c1 float64 = Big
-       c2 float64 = Big * Big          // ERROR "overflow"
-       c3 float64 = float64(Big) * Big // ERROR "overflow"
-       c4         = Big * Big          // ERROR "overflow"
+       c2 float64 = Big * Big          // ERROR "overflow|cannot convert"
+       c3 float64 = float64(Big) * Big // ERROR "overflow|cannot convert"
+       c4         = Big * Big          // ERROR "overflow|cannot convert"
        c5         = Big / 0            // ERROR "division by zero"
        c6         = 1000 % 1e3         // ERROR "invalid operation|expected integer type"
 )
@@ -87,8 +87,8 @@ func main() {
        f(Bool)             // ERROR "convert|wrong type|cannot|incompatible"
 }
 
-const ptr = nil // ERROR "const.*nil"
+const ptr = nil // ERROR "const.*nil|not constant"
 const _ = string([]byte(nil)) // ERROR "is not a? ?constant"
 const _ = uintptr(unsafe.Pointer((*int)(nil))) // ERROR "is not a? ?constant"
-const _ = unsafe.Pointer((*int)(nil)) // ERROR "cannot be nil|invalid constant type|is not a constant"
-const _ = (*int)(nil) // ERROR "cannot be nil|invalid constant type|is not a constant"
+const _ = unsafe.Pointer((*int)(nil)) // ERROR "cannot be nil|invalid constant type|is not a constant|not constant"
+const _ = (*int)(nil) // ERROR "cannot be nil|invalid constant type|is not a constant|not constant"
index d104a2fa7194169cac41bc712cdafd34e08c7d2e..f0de37be15ecab9c472e034a774be8100391eb70 100644 (file)
@@ -11,7 +11,7 @@ package main
 
 const (
        A int = 1
-       B byte; // ERROR "type without expr|expected .=."
+       B byte; // ERROR "type without expr|expected .=.|missing init expr"
 )
 
 const LargeA = 1000000000000000000
@@ -23,7 +23,7 @@ const AlsoLargeA = LargeA << 400 << 400 >> 400 >> 400 // GC_ERROR "constant shif
 // Issue #42732.
 
 const a = 1e+500000000
-const b = a * a // ERROR "constant multiplication overflow"
+const b = a * a // ERROR "constant multiplication overflow|not representable"
 const c = b * b
 
 const MaxInt512 = (1<<256 - 1) * (1<<256 + 1)
index c500638929ac78bb5ac9c9249efd75a80900dcc9..e7044b24530eb70dc7e2045e1da11910a7bf72eb 100644 (file)
@@ -22,7 +22,7 @@ func _() {
        var t T
        var u struct{}
        s = s
-       s = t // ERROR "cannot use .* in assignment"
+       s = t // ERROR "cannot use .* in assignment|incompatible type"
        s = u
        s = S(s)
        s = S(t)
@@ -42,12 +42,12 @@ func _() {
                x int "bar"
        }
        s = s
-       s = t // ERROR "cannot use .* in assignment"
-       s = u // ERROR "cannot use .* in assignment"
+       s = t // ERROR "cannot use .* in assignment|incompatible type"
+       s = u // ERROR "cannot use .* in assignment|incompatible type"
        s = S(s)
        s = S(t)
        s = S(u)
-       t = u // ERROR "cannot use .* in assignment"
+       t = u // ERROR "cannot use .* in assignment|incompatible type"
        t = T(u)
 }
 
@@ -63,12 +63,12 @@ func _() {
                x E "bar"
        }
        s = s
-       s = t // ERROR "cannot use .* in assignment"
-       s = u // ERROR "cannot use .* in assignment"
+       s = t // ERROR "cannot use .* in assignment|incompatible type"
+       s = u // ERROR "cannot use .* in assignment|incompatible type"
        s = S(s)
        s = S(t)
        s = S(u)
-       t = u // ERROR "cannot use .* in assignment"
+       t = u // ERROR "cannot use .* in assignment|incompatible type"
        t = T(u)
 }
 
@@ -91,12 +91,12 @@ func _() {
                } "bar"
        }
        s = s
-       s = t // ERROR "cannot use .* in assignment"
-       s = u // ERROR "cannot use .* in assignment"
+       s = t // ERROR "cannot use .* in assignment|incompatible type"
+       s = u // ERROR "cannot use .* in assignment|incompatible type"
        s = S(s)
        s = S(t)
        s = S(u)
-       t = u // ERROR "cannot use .* in assignment"
+       t = u // ERROR "cannot use .* in assignment|incompatible type"
        t = T(u)
 }
 
@@ -117,12 +117,12 @@ func _() {
                x E2 "bar"
        }
        s = s
-       s = t // ERROR "cannot use .* in assignment"
-       s = u // ERROR "cannot use .* in assignment"
+       s = t // ERROR "cannot use .* in assignment|incompatible type"
+       s = u // ERROR "cannot use .* in assignment|incompatible type"
        s = S(s)
        s = S(t) // ERROR "cannot convert"
        s = S(u) // ERROR "cannot convert"
-       t = u    // ERROR "cannot use .* in assignment"
+       t = u    // ERROR "cannot use .* in assignment|incompatible type"
        t = T(u)
 }
 
@@ -142,12 +142,12 @@ func _() {
        var t T
        var u struct{ f func(E) }
        s = s
-       s = t // ERROR "cannot use .* in assignment"
-       s = u // ERROR "cannot use .* in assignment"
+       s = t // ERROR "cannot use .* in assignment|incompatible type"
+       s = u // ERROR "cannot use .* in assignment|incompatible type"
        s = S(s)
        s = S(t)
        s = S(u) // ERROR "cannot convert"
-       t = u    // ERROR "cannot use .* in assignment"
+       t = u    // ERROR "cannot use .* in assignment|incompatible type"
        t = T(u) // ERROR "cannot convert"
 }
 
@@ -160,12 +160,12 @@ func _() {
        var t *T
        var u *struct{}
        s = s
-       s = t // ERROR "cannot use .* in assignment"
-       s = u // ERROR "cannot use .* in assignment"
+       s = t // ERROR "cannot use .* in assignment|incompatible type"
+       s = u // ERROR "cannot use .* in assignment|incompatible type"
        s = (*S)(s)
        s = (*S)(t)
        s = (*S)(u)
-       t = u // ERROR "cannot use .* in assignment"
+       t = u // ERROR "cannot use .* in assignment|incompatible type"
        t = (*T)(u)
 }
 
@@ -180,12 +180,12 @@ func _() {
                x int "bar"
        }
        s = s
-       s = t // ERROR "cannot use .* in assignment"
-       s = u // ERROR "cannot use .* in assignment"
+       s = t // ERROR "cannot use .* in assignment|incompatible type"
+       s = u // ERROR "cannot use .* in assignment|incompatible type"
        s = (*S)(s)
        s = (*S)(t)
        s = (*S)(u)
-       t = u // ERROR "cannot use .* in assignment"
+       t = u // ERROR "cannot use .* in assignment|incompatible type"
        t = (*T)(u)
 }
 
@@ -201,12 +201,12 @@ func _() {
                x E "bar"
        }
        s = s
-       s = t // ERROR "cannot use .* in assignment"
-       s = u // ERROR "cannot use .* in assignment"
+       s = t // ERROR "cannot use .* in assignment|incompatible type"
+       s = u // ERROR "cannot use .* in assignment|incompatible type"
        s = (*S)(s)
        s = (*S)(t)
        s = (*S)(u)
-       t = u // ERROR "cannot use .* in assignment"
+       t = u // ERROR "cannot use .* in assignment|incompatible type"
        t = (*T)(u)
 }
 
@@ -229,12 +229,12 @@ func _() {
                } "bar"
        }
        s = s
-       s = t // ERROR "cannot use .* in assignment"
-       s = u // ERROR "cannot use .* in assignment"
+       s = t // ERROR "cannot use .* in assignment|incompatible type"
+       s = u // ERROR "cannot use .* in assignment|incompatible type"
        s = (*S)(s)
        s = (*S)(t)
        s = (*S)(u)
-       t = u // ERROR "cannot use .* in assignment"
+       t = u // ERROR "cannot use .* in assignment|incompatible type"
        t = (*T)(u)
 }
 
@@ -255,12 +255,12 @@ func _() {
                x E2 "bar"
        }
        s = s
-       s = t // ERROR "cannot use .* in assignment"
-       s = u // ERROR "cannot use .* in assignment"
+       s = t // ERROR "cannot use .* in assignment|incompatible type"
+       s = u // ERROR "cannot use .* in assignment|incompatible type"
        s = (*S)(s)
        s = (*S)(t) // ERROR "cannot convert"
        s = (*S)(u) // ERROR "cannot convert"
-       t = u       // ERROR "cannot use .* in assignment"
+       t = u       // ERROR "cannot use .* in assignment|incompatible type"
        t = (*T)(u)
 }
 
@@ -280,12 +280,12 @@ func _() {
        var t *T
        var u *struct{ f func(E) }
        s = s
-       s = t // ERROR "cannot use .* in assignment"
-       s = u // ERROR "cannot use .* in assignment"
+       s = t // ERROR "cannot use .* in assignment|incompatible type"
+       s = u // ERROR "cannot use .* in assignment|incompatible type"
        s = (*S)(s)
        s = (*S)(t)
        s = (*S)(u) // ERROR "cannot convert"
-       t = u       // ERROR "cannot use .* in assignment"
+       t = u       // ERROR "cannot use .* in assignment|incompatible type"
        t = (*T)(u) // ERROR "cannot convert"
 }
 
@@ -305,11 +305,11 @@ func _() {
        var t *T
        var u *struct{ f func(E) }
        s = s
-       s = t // ERROR "cannot use .* in assignment"
-       s = u // ERROR "cannot use .* in assignment"
+       s = t // ERROR "cannot use .* in assignment|incompatible type"
+       s = u // ERROR "cannot use .* in assignment|incompatible type"
        s = (*S)(s)
        s = (*S)(t)
        s = (*S)(u) // ERROR "cannot convert"
-       t = u       // ERROR "cannot use .* in assignment"
+       t = u       // ERROR "cannot use .* in assignment|incompatible type"
        t = (*T)(u) // ERROR "cannot convert"
 }
index 1c66c89e8800757618a80a0a120b9106584661a3..9d2eee79c5b63156547d17f0ca971714e8978838 100644 (file)
@@ -17,8 +17,8 @@ var x2 string = string(1)
 var x3 = int(1.5)     // ERROR "convert|truncate"
 var x4 int = int(1.5) // ERROR "convert|truncate"
 var x5 = "a" + string(1)
-var x6 = int(1e100)      // ERROR "overflow"
-var x7 = float32(1e1000) // ERROR "overflow"
+var x6 = int(1e100)      // ERROR "overflow|cannot convert"
+var x7 = float32(1e1000) // ERROR "overflow|cannot convert"
 
 // unsafe.Pointer can only convert to/from uintptr
 var _ = string(unsafe.Pointer(uintptr(65)))  // ERROR "convert|conversion"
@@ -34,7 +34,7 @@ var bad4 = "a" + 1   // ERROR "literals|incompatible|convert|invalid"
 var bad5 = "a" + 'a' // ERROR "literals|incompatible|convert|invalid"
 
 var bad6 int = 1.5       // ERROR "convert|truncate"
-var bad7 int = 1e100     // ERROR "overflow"
+var bad7 int = 1e100     // ERROR "overflow|truncated to int"
 var bad8 float32 = 1e200 // ERROR "overflow"
 
 // but these implicit conversions are okay
@@ -48,8 +48,8 @@ var _ = []rune("abc")
 var _ = []byte("abc")
 
 // implicit is not
-var _ []int = "abc"  // ERROR "cannot use|incompatible|invalid"
-var _ []byte = "abc" // ERROR "cannot use|incompatible|invalid"
+var _ []int = "abc"  // ERROR "cannot use|incompatible|invalid|cannot convert"
+var _ []byte = "abc" // ERROR "cannot use|incompatible|invalid|cannot convert"
 
 // named string is okay
 type Tstring string
@@ -70,5 +70,5 @@ var _ = Trune("abc") // ok
 var _ = Tbyte("abc") // ok
 
 // implicit is still not
-var _ Trune = "abc" // ERROR "cannot use|incompatible|invalid"
-var _ Tbyte = "abc" // ERROR "cannot use|incompatible|invalid"
+var _ Trune = "abc" // ERROR "cannot use|incompatible|invalid|cannot convert"
+var _ Tbyte = "abc" // ERROR "cannot use|incompatible|invalid|cannot convert"
index e1fa105584a1d6ac30c447abaafa0b01a0b4fdb3..c0760f71904879206c81a7bbc6e7e45d27f58b85 100644 (file)
@@ -17,11 +17,11 @@ func main() {
        _ = copy()        // ERROR "not enough arguments"
        _ = copy(1, 2, 3) // ERROR "too many arguments"
 
-       _ = copy(si, "hi") // ERROR "have different element types.*int.*string"
+       _ = copy(si, "hi") // ERROR "have different element types(.*int.*string| int and byte)"
        _ = copy(si, sf)   // ERROR "have different element types.*int.*float64"
 
-       _ = copy(1, 2)  // ERROR "must be slices; have int, int"
-       _ = copy(1, si) // ERROR "first argument to copy should be"
-       _ = copy(si, 2) // ERROR "second argument to copy should be"
+       _ = copy(1, 2)  // ERROR "must be slices; have int, int|expects slice arguments"
+       _ = copy(1, si) // ERROR "first argument to copy should be|expects slice arguments"
+       _ = copy(si, 2) // ERROR "second argument to copy should be|expects slice arguments"
 
 }
index d2cf88afcb24ff04a9c2f6514c731a7ed174bdd7..5c3a1d7c129ba8c6019819fda94aba4ddd527c97 100644 (file)
@@ -7,5 +7,5 @@
 package main
 
 func f (x,             // GCCGO_ERROR "previous"
-       x int) {        // ERROR "duplicate argument|redefinition"
+       x int) {        // ERROR "duplicate argument|redefinition|redeclared"
 }
index 1cc50036559d661000ab187dff72c3e48e207387..24c2dff9339a689b749f5ac79046a53d7880db68 100644 (file)
@@ -8,4 +8,5 @@ package main
 
 func main() {
        var s string = nil;     // ERROR "illegal|invalid|incompatible|cannot"
+       _ = s
 }
index c25d2883704945e5cfa988ed9dc0ddda639222ad..40e6dd1b6f129a1a2b91ef00d7fe0319c7fd98e6 100644 (file)
@@ -6,7 +6,7 @@
 
 package main
 
-const x x = 2 // ERROR "loop|type"
+const x x = 2 // ERROR "loop|type|cycle"
 
 /*
 bug081.go:3: first constant must evaluate an expression
index 320bd57f5c17fb9cf6ff0b17f598a02ac6c9af9a..6d30cca017b7467116c8680f0980569f501cdc70 100644 (file)
@@ -42,5 +42,5 @@ func main() {
 
        const h float64 = 3.14;
        i = h;  // ERROR "convert|incompatible|cannot"
-       i = int(h);     // ERROR "truncate"
+       i = int(h);     // ERROR "truncate|cannot convert"
 }
index fb4eb9f3adebed21309c3940a568e071c181a088..5640cf263a8e8a6e4baaf863c43560f94b56987f 100644 (file)
@@ -8,5 +8,5 @@ package main
 
 func main() {
        // should allow at most 2 sizes
-       a := make([]int, 10, 20, 30, 40); // ERROR "too many"
+       a := make([]int, 10, 20, 30, 40); // ERROR "too many|expects 2 or 3 arguments; found 5"
 }
index 0ebbd26069e16ba2f2e57abcd27cbcf874f66b98..2c9d120ed069bf7b4a74984a999123ab641ebc3b 100644 (file)
@@ -9,4 +9,5 @@ package main
 func main() {
        const a uint64 = 10;
        var b int64 = a;        // ERROR "convert|cannot|incompatible"
+       _ = b
 }
index e334566c79b9c157fab2d7b3f3e70e84a229d61d..b75e8338de213006087e81fde6125604b6bf9ecb 100644 (file)
@@ -7,5 +7,5 @@
 package main
 
 type T struct {
-       x, x int  // ERROR "duplicate"
+       x, x int  // ERROR "duplicate|redeclared"
 }
index d69f6bef03a70d77327eec3692731fd49727f165..f3e0543cd744b461db12bad77b177eed30075884 100644 (file)
@@ -6,6 +6,4 @@
 
 package main
 
-func main() {
-       x⊛y := 1;     // ERROR "identifier"
-}
+var x⊛y int  // ERROR "invalid character .* in identifier"
index 5fca4b22bc5539ba3f91f580d232aacab90292a5..88210a59b3e520c780f47cd0a1738b31f57684f0 100644 (file)
@@ -9,6 +9,6 @@ package main
 func f() (int, bool) { return 0, true }
 
 func main() {
-       x, y := f(), 2; // ERROR "multi"
+       x, y := f(), 2; // ERROR "multi|2-valued"
        _, _ = x, y
 }
index 679aaed1f2d05eb75c5240744276c6dd1b125899..a22e6a24824e66c0b2061f3bbdb6ec0d94b0b3b0 100644 (file)
@@ -8,4 +8,6 @@ package main
 
 import "fmt"   // GCCGO_ERROR "previous"
 
-var fmt int    // ERROR "redecl|redefinition"
+var _ = fmt.Println // avoid imported and not used error
+
+var fmt int    // ERROR "redecl|redefinition|fmt already declared"
index 1e0d9d1f34d62f554d4ab1c4413da85be2259af0..789696df0cc9cd548e63ad6f9510ee836513e5c7 100644 (file)
@@ -11,8 +11,8 @@ var s string;
 var m map[string]int;
 
 func main() {
-       println(t["hi"]); // ERROR "non-integer slice index|must be integer"
-       println(s["hi"]); // ERROR "non-integer string index|must be integer"
-       println(m[0]);    // ERROR "cannot use.*as type string"
+       println(t["hi"]); // ERROR "non-integer slice index|must be integer|cannot convert"
+       println(s["hi"]); // ERROR "non-integer string index|must be integer|cannot convert"
+       println(m[0]);    // ERROR "cannot use.*as type string|cannot convert"
 }
 
index b27cc7db1a91620bf6804de1d4d59fab6029a05a..5546d0c8899185bec6ee8e5fc9c9bd4823c0267d 100644 (file)
@@ -9,6 +9,6 @@
 
 package main
 
-type A struct {        a A }   // ERROR "recursive"
+type A struct {        a A }   // ERROR "recursive|cycle"
 func foo()             { new(A).bar() }
 func (a A) bar()       {}
index 29ae53cb713c45ab97aefb2bc029bf57a5c49589..50082cbab1beeed5522803a4cb5ee08831bba05c 100644 (file)
@@ -18,4 +18,4 @@ func f() {
        }
 }
 
-var m = map[string]F{"f": f} // ERROR "initialization loop|depends upon itself"
+var m = map[string]F{"f": f} // ERROR "initialization loop|depends upon itself|initialization cycle"
index d2fd67cf32f3fbff347ff4e81987c74a95378fe8..4ff83019df05c2a4348f4fba0bde28504ab27d4d 100644 (file)
@@ -6,5 +6,5 @@
 
 package main
 
-type T T               // ERROR "recursive"
+type T T               // ERROR "recursive|cycle"
 
index a30202fa2c75cd81542d67756981c8416087e80d..3cf1142a24ac49586e6f660615dfb2c13c2b8888 100644 (file)
@@ -14,7 +14,7 @@ func main() {
        // make sure error mentions that
        // name is unexported, not just "name not found".
 
-       t.common.name = nil // ERROR "unexported"
+       t.common.name = nil // ERROR "unexported|undefined"
 
-       println(testing.anyLowercaseName("asdf")) // ERROR "unexported"
+       println(testing.anyLowercaseName("asdf")) // ERROR "unexported|undefined"
 }
index afec57f037ad6ba7fd401347b32fce52951a166f..9a9d4c902d2f6e281cffb74434c8457a6eb24b01 100644 (file)
@@ -8,6 +8,6 @@
 
 package main
 
-type A [...]int        // ERROR "outside of array literal"
+type A [...]int        // ERROR "outside of array literal|invalid use of \[\.\.\.\]"
 
 
index 3fc7fb2eeff7cf002d43bbfaedf4ed3d971baf3a..fea6829992f57ac699f7fe08f934dfec767b7a38 100644 (file)
@@ -9,14 +9,14 @@
 package main
 
 func f1() {
-       a, b := f()     // ERROR "assignment mismatch|does not match"
+       a, b := f()     // ERROR "assignment mismatch|does not match|cannot initialize"
        _ = a
        _ = b
 }
 
 func f2() {
        var a, b int
-       a, b = f()      // ERROR "assignment mismatch|does not match"
+       a, b = f()      // ERROR "assignment mismatch|does not match|cannot assign"
        _ = a
        _ = b
 }
index e6528ae46a21b29d4d922da3d060e7d7b3e63a43..74d7bbb92383b6b602ca7fb3988239a6b902f1f1 100644 (file)
@@ -10,6 +10,6 @@ import "unsafe"
 
 func main() {
        var x unsafe.Pointer
-       println(*x) // ERROR "invalid indirect.*unsafe.Pointer"
+       println(*x) // ERROR "invalid indirect.*unsafe.Pointer|cannot indirect"
        var _ = (unsafe.Pointer)(nil).foo  // ERROR "foo"
 }
index 75d620cde533e266848dceea1ab007061f63a9cb..dfd8be80050edae795a665adb4d3ea9e0d9c902b 100644 (file)
@@ -19,7 +19,7 @@ func h() (_ int, _ error) {
 }
 
 func i() (int, error) {
-       return // ERROR "not enough arguments to return"
+       return // ERROR "not enough arguments to return|wrong number of return values"
 }
 
 func f1() (_ int, err error) {
index 542a6eab03d2d5f3e418866938dbe7df5acd48a8..117b28647a81c2f9fce8d68cb4a80adb32d1f472 100644 (file)
@@ -13,6 +13,6 @@ func main() {
        switch t := x.(type) {
        case 0:         // ERROR "type"
                t.x = 1
-               x.x = 1 // ERROR "type interface \{\}|reference to undefined field or method|interface with no methods"
+               x.x = 1 // ERROR "type interface \{\}|reference to undefined field or method|interface with no methods|undefined"
        }
 }
index f90f6f32cc71cd88ceba9e2e30401dff04fc23bc..ccf93a6d956c7216be9179b9760c3aacf184a9fc 100644 (file)
@@ -9,7 +9,7 @@
 package p
 
 type a interface {
-       foo(x int) (x int) // ERROR "duplicate argument|redefinition"
+       foo(x int) (x int) // ERROR "duplicate argument|redefinition|redeclared"
 }
 
 /*
index cdce1cfbe2c5753f06a29d0f6c82f63827747e77..39f91d43a93e7e764b29a6fa15f581e93ebbd53d 100644 (file)
@@ -12,4 +12,4 @@ func (T) m() {} // GCCGO_ERROR "previous"
 func (T) m() {} // ERROR "T[.]m redeclared|redefinition"
 
 func (*T) p() {} // GCCGO_ERROR "previous"
-func (*T) p() {} // ERROR "[(][*]T[)][.]p redeclared|redefinition"
+func (*T) p() {} // ERROR "[(][*]T[)][.]p redeclared|redefinition|redeclared"
index e9db50e88e97c0dcc07ad32c4075900bcbc639d2..0a4cbedd95ec6efa9d6e10b1158acf54d753b659 100644 (file)
@@ -15,7 +15,7 @@ func bla1() bool {
 
 func bla5() bool {
        _ = 1
-       false  // ERROR "false evaluated but not used|value computed is not used"
+       false  // ERROR "false evaluated but not used|value computed is not used|is not used"
        _ = 2
        return false
 }
index 771d13d4353d60e2c5e427858507dbbf99b393fb..98d6b0c82289ada9d1f90ce40da9a21e6426f577 100644 (file)
@@ -10,7 +10,7 @@
 package main
 
 var (
-       a = iota  // ERROR "undefined: iota|iota is only defined in const"
-       b = iota  // ERROR "undefined: iota|iota is only defined in const"
-       c = iota  // ERROR "undefined: iota|iota is only defined in const"
+       a = iota  // ERROR "undefined: iota|iota is only defined in const|cannot use iota outside constant declaration"
+       b = iota  // ERROR "undefined: iota|iota is only defined in const|cannot use iota outside constant declaration"
+       c = iota  // ERROR "undefined: iota|iota is only defined in const|cannot use iota outside constant declaration"
 )
index 3a626e523ce58578bc1766dad99d3e8e13211dcc..eb51b9ee86ec6597df9e8af7e6a80952a452cbde 100644 (file)
@@ -19,6 +19,6 @@ func main() {
        p.m()
 
        q := &p
-       q.m()  // ERROR "requires explicit dereference"
-       q.pm() // ERROR "requires explicit dereference"
+       q.m()  // ERROR "requires explicit dereference|undefined"
+       q.pm() // ERROR "requires explicit dereference|undefined"
 }
index 5638123d5028f5c80cdb67eee8bb604a36f847d8..aa078b6ff45c30158817a9268f36ccc48ab97c60 100644 (file)
@@ -14,5 +14,5 @@
 package main
 
 func main() {
-       1 + 2 // ERROR "1 \+ 2 evaluated but not used|value computed is not used"
+       1 + 2 // ERROR "1 \+ 2 evaluated but not used|value computed is not used|is not used"
 }
index dc2ecd61fbd66f51d6705fdc90c4f4ba9472093d..543ee10ac6065710977688fee44e06d1304f005e 100644 (file)
@@ -8,6 +8,6 @@
 
 package main
 func main() {
-       if 2e9 { }      // ERROR "2e.09|expected bool"
-       if 3.14+1i { }  // ERROR "3.14 . 1i|expected bool"
+       if 2e9 { }      // ERROR "2e.09|expected bool|non-boolean condition in if statement"
+       if 3.14+1i { }  // ERROR "3.14 . 1i|expected bool|non-boolean condition in if statement"
 }
index 889c8b0c12598d4d302962f40879a3f55b495e64..0899d1fc216b87a60d2b323f22ce3f9f0eb6f56b 100644 (file)
@@ -7,6 +7,6 @@
 // Issue 2451, 2452 
 package foo
 
-func f() error { return 0 } // ERROR "cannot use 0 .type int.|has no methods"
+func f() error { return 0 } // ERROR "cannot use 0 (.type int.)?|has no methods"
 
-func g() error { return -1 }  // ERROR "cannot use -1 .type int.|has no methods"
+func g() error { return -1 }  // ERROR "cannot use -1 (.type int.)?|has no methods"
index 14804c8471540694032dd449f737fd2191db437b..167e64e72c731a8f5185724469e71d3c992ac0e5 100644 (file)
@@ -9,4 +9,4 @@ package foo
 
 func fn(a float32) {}
 
-var f func(arg int) = fn  // ERROR "cannot use fn .type func.float32.. as type func.int. in assignment|different parameter types"
+var f func(arg int) = fn  // ERROR "cannot use fn .type func.float32.. as type func.int. in assignment|different parameter types|incompatible type"
index 7ce9e137035a4a679728f710b98d3129e96c1e9a..4ab24fb521a3dbd6650474a6be99c21f3152937b 100644 (file)
@@ -12,5 +12,5 @@ import "unsafe"
 
 func main() {
        var x *int
-       _ = unsafe.Pointer(x) - unsafe.Pointer(x) // ERROR "operator - not defined on unsafe.Pointer|expected integer, floating, or complex type"
+       _ = unsafe.Pointer(x) - unsafe.Pointer(x) // ERROR "(operator|operation) - not defined on unsafe.Pointer|expected integer, floating, or complex type"
 }
index 6188e3ee0cc642365d4bad6f04d551326e54f544..db8d652814d1e1ebecce5c716f11d5af0d6b9eff 100644 (file)
@@ -9,5 +9,5 @@ package main
 // Issue 2623
 var m = map[string]int {
        "abc":1,
-       1:2, // ERROR "cannot use 1.*as type string in map key|incompatible type"
+       1:2, // ERROR "cannot use 1.*as type string in map key|incompatible type|cannot convert"
 }
index 9fc3532f1d671d15b6f1bd9683aff854760e70a6..74b55cce18ae02b8f5ae6e28fb1c24cf7b21a106 100644 (file)
@@ -10,4 +10,4 @@ type T struct {
        X int
 }
 
-func (t *T) X() {} // ERROR "type T has both field and method named X|redeclares struct field name"
+func (t *T) X() {} // ERROR "type T has both field and method named X|redeclares struct field name|field and method with the same name"
index 64d86b34006e6f79b571affd866f4ff344d1878b..4e63e867b852669720b40ac84c15c8692ed23437 100644 (file)
@@ -13,10 +13,10 @@ func Two() (a, b int)
 
 // F used to compile.
 func F() (x interface{}, y int) {
-       return Two(), 0 // ERROR "single-value context"
+       return Two(), 0 // ERROR "single-value context|2\-valued"
 }
 
 // Recursive used to trigger an internal compiler error.
 func Recursive() (x interface{}, y int) {
-       return Recursive(), 0 // ERROR "single-value context"
+       return Recursive(), 0 // ERROR "single-value context|2\-valued"
 }
index bae5ee0aeb01924c7bfc353da8852b72d6a86f78..c6962e48c11043bd1ae159a0731d8441ed456543 100644 (file)
@@ -8,6 +8,8 @@ package main
 
 import "os"
 
+var _ = os.Open // avoid imported and not used error
+
 type T struct {
        File int
 }
index c7f92379c84a16902018d79ff28d9673ce327630..ed546bf74163da11b865a9ba0e87af246c3a7e5f 100644 (file)
@@ -9,11 +9,11 @@
 
 package main
 
-const a = a // ERROR "refers to itself|definition loop"
+const a = a // ERROR "refers to itself|definition loop|initialization loop"
 
 const (
        X    = A
-       A    = B // ERROR "refers to itself|definition loop"
+       A    = B // ERROR "refers to itself|definition loop|initialization loop"
        B    = D
        C, D = 1, A
 )
index e60af6c8e23b2dd6b0a11f85981f2e8585e766df..150d660abc20e6e552f2f175146a12287b3f7b1b 100644 (file)
@@ -14,11 +14,11 @@ func G() (int, int, int) {
 }
 
 func F() {
-       a, b := G()     // ERROR "mismatch"
-       a, b = G()      // ERROR "mismatch"
+       a, b := G()     // ERROR "mismatch|cannot initialize"
+       a, b = G()      // ERROR "mismatch|cannot assign"
        _, _ = a, b
 }
 
 func H() (int, int) {
-       return G()      // ERROR "too many|mismatch"
+       return G()      // ERROR "too many|mismatch|wrong number"
 }
index 933badfd2f3ebd40b9b2b536d482f2ddb91da114..89ef23c1a86e555cb175daedb55c550b3c874015 100644 (file)
@@ -10,7 +10,7 @@
 package main
 
 type I interface {
-       int // ERROR "interface contains embedded non-interface"
+       int // ERROR "interface contains embedded non-interface|not an interface"
 }
 
 func New() I {
index e0c6a9f0baa3d2a5c97f4240dac783ca310640b6..7f08e7fa3c254cc19c77617a8b145eea1f6a3efd 100644 (file)
@@ -18,14 +18,14 @@ func main() {
 
        // Any implementation must be able to handle these constants at
        // compile time (even though they cannot be assigned to a float64).
-       var _ = 1e646456992  // ERROR "1e\+646456992 overflows float64|floating-point constant overflow|exponent too large"
-       var _ = 1e64645699   // ERROR "1e\+64645699 overflows float64|floating-point constant overflow|exponent too large"
-       var _ = 1e6464569    // ERROR "1e\+6464569 overflows float64|floating-point constant overflow|exponent too large"
-       var _ = 1e646456     // ERROR "1e\+646456 overflows float64|floating-point constant overflow|exponent too large"
-       var _ = 1e64645      // ERROR "1e\+64645 overflows float64|floating-point constant overflow|exponent too large"
-       var _ = 1e6464       // ERROR "1e\+6464 overflows float64|floating-point constant overflow"
-       var _ = 1e646        // ERROR "1e\+646 overflows float64|floating-point constant overflow"
-       var _ = 1e309        // ERROR "1e\+309 overflows float64|floating-point constant overflow"
+       var _ = 1e646456992  // ERROR "1e\+646456992 overflows float64|floating-point constant overflow|exponent too large|overflows float64"
+       var _ = 1e64645699   // ERROR "1e\+64645699 overflows float64|floating-point constant overflow|exponent too large|overflows float64"
+       var _ = 1e6464569    // ERROR "1e\+6464569 overflows float64|floating-point constant overflow|exponent too large|overflows float64"
+       var _ = 1e646456     // ERROR "1e\+646456 overflows float64|floating-point constant overflow|exponent too large|overflows float64"
+       var _ = 1e64645      // ERROR "1e\+64645 overflows float64|floating-point constant overflow|exponent too large|overflows float64"
+       var _ = 1e6464       // ERROR "1e\+6464 overflows float64|floating-point constant overflow|overflows float64"
+       var _ = 1e646        // ERROR "1e\+646 overflows float64|floating-point constant overflow|overflows float64"
+       var _ = 1e309        // ERROR "1e\+309 overflows float64|floating-point constant overflow|overflows float64"
 
        var _ = 1e308
 }
index 63dbf05d731ac6109e18d074ab392afd7099e59e..1ef8735a525a40366b4f22809a3f3fe9ac2fe895 100644 (file)
@@ -8,4 +8,4 @@ package a
 
 import "fmt"  // GC_ERROR "imported and not used"
 
-const n = fmt // ERROR "fmt without selector|unexpected reference to package"
+const n = fmt // ERROR "fmt without selector|unexpected reference to package|use of package fmt not in selector"
index 8acd18fccb90dab033c96124c550414ca1681bf1..0965e88d74661272d27c3046181f02c24793a4bb 100644 (file)
@@ -9,9 +9,9 @@
 
 package issue11371
 
-const a int = 1.1        // ERROR "constant 1.1 truncated to integer|floating-point constant truncated to integer"
-const b int = 1e20       // ERROR "overflows int|integer constant overflow"
-const c int = 1 + 1e-70  // ERROR "constant truncated to integer"
-const d int = 1 - 1e-70  // ERROR "constant truncated to integer"
-const e int = 1.00000001 // ERROR "constant truncated to integer"
-const f int = 0.00000001 // ERROR "constant 1e-08 truncated to integer|floating-point constant truncated to integer"
+const a int = 1.1        // ERROR "constant 1.1 truncated to integer|floating-point constant truncated to integer|truncated to int"
+const b int = 1e20       // ERROR "overflows int|integer constant overflow|truncated to int"
+const c int = 1 + 1e-70  // ERROR "constant truncated to integer|truncated to int"
+const d int = 1 - 1e-70  // ERROR "constant truncated to integer|truncated to int"
+const e int = 1.00000001 // ERROR "constant truncated to integer|truncated to int"
+const f int = 0.00000001 // ERROR "constant 1e-08 truncated to integer|floating-point constant truncated to integer|truncated to int"
index b43032deac45953d0c54525c05bde43d83db64af..183ed133de7767da2c34603e9103925e85d0fa55 100644 (file)
@@ -13,28 +13,28 @@ const x complex64 = 0
 const y complex128 = 0
 
 var _ = x / 1e-20
-var _ = x / 1e-50   // GC_ERROR "complex division by zero"
-var _ = x / 1e-1000 // GC_ERROR "complex division by zero"
+var _ = x / 1e-50   // GC_ERROR "division by zero"
+var _ = x / 1e-1000 // GC_ERROR "division by zero"
 var _ = x / 1e-20i
-var _ = x / 1e-50i   // GC_ERROR "complex division by zero"
-var _ = x / 1e-1000i // GC_ERROR "complex division by zero"
+var _ = x / 1e-50i   // GC_ERROR "division by zero"
+var _ = x / 1e-1000i // GC_ERROR "division by zero"
 
 var _ = x / 1e-45 // smallest positive float32
 
 var _ = x / (1e-20 + 1e-20i)
 var _ = x / (1e-50 + 1e-20i)
 var _ = x / (1e-20 + 1e-50i)
-var _ = x / (1e-50 + 1e-50i)     // GC_ERROR "complex division by zero"
-var _ = x / (1e-1000 + 1e-1000i) // GC_ERROR "complex division by zero"
+var _ = x / (1e-50 + 1e-50i)     // GC_ERROR "division by zero"
+var _ = x / (1e-1000 + 1e-1000i) // GC_ERROR "division by zero"
 
 var _ = y / 1e-50
-var _ = y / 1e-1000 // GC_ERROR "complex division by zero"
+var _ = y / 1e-1000 // GC_ERROR "division by zero"
 var _ = y / 1e-50i
-var _ = y / 1e-1000i // GC_ERROR "complex division by zero"
+var _ = y / 1e-1000i // GC_ERROR "division by zero"
 
 var _ = y / 5e-324 // smallest positive float64
 
 var _ = y / (1e-50 + 1e-50)
 var _ = y / (1e-1000 + 1e-50i)
 var _ = y / (1e-50 + 1e-1000i)
-var _ = y / (1e-1000 + 1e-1000i) // GC_ERROR "complex division by zero"
+var _ = y / (1e-1000 + 1e-1000i) // GC_ERROR "division by zero"
index 86ecf9ac4b859c653dabfdaa2f63c38517e577ff..eb4bfe8964e82cfdb839441879d293dba02e0ee7 100644 (file)
@@ -12,6 +12,6 @@ func f()
 
 func s(x interface{}) {
        switch x {
-       case f: // ERROR "invalid case f \(type func\(\)\) in switch \(incomparable type\)"
+       case f: // ERROR "invalid case f \(type func\(\)\) in switch \(incomparable type\)|cannot compare"
        }
 }
index 31a663eb1f69459093f2fe64c8bc82614fcfa9c8..b22fa0fb4e576dcb67f56783e31681e8754983a9 100644 (file)
@@ -11,15 +11,15 @@ package main
 var t struct{}
 
 func main() {
-       _ = []int{-1: 0}    // ERROR "index must be non\-negative integer constant|index expression is negative"
-       _ = [10]int{-1: 0}  // ERROR "index must be non\-negative integer constant|index expression is negative"
-       _ = [...]int{-1: 0} // ERROR "index must be non\-negative integer constant|index expression is negative"
+       _ = []int{-1: 0}    // ERROR "index must be non\-negative integer constant|index expression is negative|must not be negative"
+       _ = [10]int{-1: 0}  // ERROR "index must be non\-negative integer constant|index expression is negative|must not be negative"
+       _ = [...]int{-1: 0} // ERROR "index must be non\-negative integer constant|index expression is negative|must not be negative"
 
        _ = []int{100: 0}
        _ = [10]int{100: 0} // ERROR "array index 100 out of bounds|out of range"
        _ = [...]int{100: 0}
 
-       _ = []int{t}    // ERROR "cannot use .* as type int in slice literal|incompatible type"
-       _ = [10]int{t}  // ERROR "cannot use .* as type int in array literal|incompatible type"
-       _ = [...]int{t} // ERROR "cannot use .* as type int in array literal|incompatible type"
+       _ = []int{t}    // ERROR "cannot use .* as (type )?int( in slice literal)?|incompatible type"
+       _ = [10]int{t}  // ERROR "cannot use .* as (type )?int( in array literal)?|incompatible type"
+       _ = [...]int{t} // ERROR "cannot use .* as (type )?int( in array literal)?|incompatible type"
 }
index 9069412ffa6234d14fa96fe75230ea27f783d82a..cab6bedee5a5f5c6ebf17f6a76261ee9d43f8e62 100644 (file)
@@ -9,17 +9,17 @@
 package main
 
 func main() {
-       const _ int64 = 1e646456992 // ERROR "integer too large|floating-point constant truncated to integer|exponent too large"
-       const _ int32 = 1e64645699  // ERROR "integer too large|floating-point constant truncated to integer|exponent too large"
-       const _ int16 = 1e6464569   // ERROR "integer too large|floating-point constant truncated to integer|exponent too large"
-       const _ int8 = 1e646456     // ERROR "integer too large|floating-point constant truncated to integer|exponent too large"
-       const _ int = 1e64645       // ERROR "integer too large|floating-point constant truncated to integer|exponent too large"
+       const _ int64 = 1e646456992 // ERROR "integer too large|floating-point constant truncated to integer|exponent too large|truncated"
+       const _ int32 = 1e64645699  // ERROR "integer too large|floating-point constant truncated to integer|exponent too large|truncated"
+       const _ int16 = 1e6464569   // ERROR "integer too large|floating-point constant truncated to integer|exponent too large|truncated"
+       const _ int8 = 1e646456     // ERROR "integer too large|floating-point constant truncated to integer|exponent too large|truncated"
+       const _ int = 1e64645       // ERROR "integer too large|floating-point constant truncated to integer|exponent too large|truncated"
 
-       const _ uint64 = 1e646456992 // ERROR "integer too large|floating-point constant truncated to integer|exponent too large"
-       const _ uint32 = 1e64645699  // ERROR "integer too large|floating-point constant truncated to integer|exponent too large"
-       const _ uint16 = 1e6464569   // ERROR "integer too large|floating-point constant truncated to integer|exponent too large"
-       const _ uint8 = 1e646456     // ERROR "integer too large|floating-point constant truncated to integer|exponent too large"
-       const _ uint = 1e64645       // ERROR "integer too large|floating-point constant truncated to integer|exponent too large"
+       const _ uint64 = 1e646456992 // ERROR "integer too large|floating-point constant truncated to integer|exponent too large|truncated"
+       const _ uint32 = 1e64645699  // ERROR "integer too large|floating-point constant truncated to integer|exponent too large|truncated"
+       const _ uint16 = 1e6464569   // ERROR "integer too large|floating-point constant truncated to integer|exponent too large|truncated"
+       const _ uint8 = 1e646456     // ERROR "integer too large|floating-point constant truncated to integer|exponent too large|truncated"
+       const _ uint = 1e64645       // ERROR "integer too large|floating-point constant truncated to integer|exponent too large|truncated"
 
-       const _ rune = 1e64645 // ERROR "integer too large|floating-point constant truncated to integer|exponent too large"
+       const _ rune = 1e64645 // ERROR "integer too large|floating-point constant truncated to integer|exponent too large|truncated"
 }
index cd2f05de5f6977c933088b51673176bdb66568af..7e859c56c5d3d6f49617096bde837a2352530a44 100644 (file)
@@ -18,21 +18,21 @@ func bug() {
        var m M
        var f F
 
-       _ = s == S(nil) // ERROR "compare.*to nil"
-       _ = S(nil) == s // ERROR "compare.*to nil"
+       _ = s == S(nil) // ERROR "compare.*to nil|operator \=\= not defined for .|cannot compare"
+       _ = S(nil) == s // ERROR "compare.*to nil|operator \=\= not defined for .|cannot compare"
        switch s {
-       case S(nil): // ERROR "compare.*to nil"
+       case S(nil): // ERROR "compare.*to nil|operator \=\= not defined for .|cannot compare"
        }
 
-       _ = m == M(nil) // ERROR "compare.*to nil"
-       _ = M(nil) == m // ERROR "compare.*to nil"
+       _ = m == M(nil) // ERROR "compare.*to nil|operator \=\= not defined for .|cannot compare"
+       _ = M(nil) == m // ERROR "compare.*to nil|operator \=\= not defined for .|cannot compare"
        switch m {
-       case M(nil): // ERROR "compare.*to nil"
+       case M(nil): // ERROR "compare.*to nil|operator \=\= not defined for .|cannot compare"
        }
 
-       _ = f == F(nil) // ERROR "compare.*to nil"
-       _ = F(nil) == f // ERROR "compare.*to nil"
+       _ = f == F(nil) // ERROR "compare.*to nil|operator \=\= not defined for .|cannot compare"
+       _ = F(nil) == f // ERROR "compare.*to nil|operator \=\= not defined for .|cannot compare"
        switch f {
-       case F(nil): // ERROR "compare.*to nil"
+       case F(nil): // ERROR "compare.*to nil|operator \=\= not defined for .|cannot compare"
        }
 }
index a9beea1f7dfb9b4f3f6472eedef9091a749b97c0..d928c1e1fa0efbe8ab954151f7a646794aa4e5e5 100644 (file)
@@ -9,10 +9,10 @@ package p
 var (
        _ [10]int
        _ [10.0]int
-       _ [float64(10)]int                // ERROR "invalid array bound"
+       _ [float64(10)]int                // ERROR "invalid array bound|must be integer"
        _ [10 + 0i]int
        _ [complex(10, 0)]int
-       _ [complex128(complex(10, 0))]int // ERROR "invalid array bound"
+       _ [complex128(complex(10, 0))]int // ERROR "invalid array bound|must be integer"
        _ ['a']int
        _ [rune(65)]int
 )
index 72c3ab0ae0ede61fb7fb1f095b251ff75c306c04..181fbef9bf7bee2a03af52d46aea9c6ec2591ddd 100644 (file)
@@ -10,7 +10,7 @@
 
 package main
 
-import "math" // ERROR "imported and not used"
+import "math" // ERROR "imported and not used|imported but not used"
 
 func main() {
 math:
index 16de2a2e31104d9be4715b2727a1245d93247157..07cf2ca2110d2b27f9a24c3baf54bf2b5ac946e2 100644 (file)
 package p
 
 // failure case in issue
-const _ int64 = 1e-10000 // ERROR "1e\-10000 truncated"
+const _ int64 = 1e-10000 // ERROR "1e\-10000 truncated|.* truncated to int64"
 
 const (
-       _ int64 = 1e10000000 // ERROR "integer too large"
-       _ int64 = 1e1000000  // ERROR "integer too large"
-       _ int64 = 1e100000   // ERROR "integer too large"
-       _ int64 = 1e10000    // ERROR "integer too large"
-       _ int64 = 1e1000     // ERROR "integer too large"
-       _ int64 = 1e100      // ERROR "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows"
+       _ int64 = 1e10000000 // ERROR "integer too large|truncated to int64"
+       _ int64 = 1e1000000  // ERROR "integer too large|truncated to int64"
+       _ int64 = 1e100000   // ERROR "integer too large|truncated to int64"
+       _ int64 = 1e10000    // ERROR "integer too large|truncated to int64"
+       _ int64 = 1e1000     // ERROR "integer too large|truncated to int64"
+       _ int64 = 1e100      // ERROR "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows|truncated to int64"
        _ int64 = 1e10
        _ int64 = 1e1
        _ int64 = 1e0
-       _ int64 = 1e-1       // ERROR "0\.1 truncated"
-       _ int64 = 1e-10      // ERROR "1e\-10 truncated"
-       _ int64 = 1e-100     // ERROR "1e\-100 truncated"
-       _ int64 = 1e-1000    // ERROR "1e\-1000 truncated"
-       _ int64 = 1e-10000   // ERROR "1e\-10000 truncated"
-       _ int64 = 1e-100000  // ERROR "1e\-100000 truncated"
-       _ int64 = 1e-1000000 // ERROR "1e\-1000000 truncated"
+       _ int64 = 1e-1       // ERROR "0\.1 truncated|.* truncated to int64"
+       _ int64 = 1e-10      // ERROR "1e\-10 truncated|.* truncated to int64"
+       _ int64 = 1e-100     // ERROR "1e\-100 truncated|.* truncated to int64"
+       _ int64 = 1e-1000    // ERROR "1e\-1000 truncated|.* truncated to int64"
+       _ int64 = 1e-10000   // ERROR "1e\-10000 truncated|.* truncated to int64"
+       _ int64 = 1e-100000  // ERROR "1e\-100000 truncated|.* truncated to int64"
+       _ int64 = 1e-1000000 // ERROR "1e\-1000000 truncated|.* truncated to int64"
 )
 
 const (
-       _ int64 = -1e10000000 // ERROR "integer too large"
-       _ int64 = -1e1000000  // ERROR "integer too large"
-       _ int64 = -1e100000   // ERROR "integer too large"
-       _ int64 = -1e10000    // ERROR "integer too large"
-       _ int64 = -1e1000     // ERROR "integer too large"
-       _ int64 = -1e100      // ERROR "\-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows"
+       _ int64 = -1e10000000 // ERROR "integer too large|truncated to int64"
+       _ int64 = -1e1000000  // ERROR "integer too large|truncated to int64"
+       _ int64 = -1e100000   // ERROR "integer too large|truncated to int64"
+       _ int64 = -1e10000    // ERROR "integer too large|truncated to int64"
+       _ int64 = -1e1000     // ERROR "integer too large|truncated to int64"
+       _ int64 = -1e100      // ERROR "\-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows|truncated to int64"
        _ int64 = -1e10
        _ int64 = -1e1
        _ int64 = -1e0
-       _ int64 = -1e-1       // ERROR "\-0\.1 truncated"
-       _ int64 = -1e-10      // ERROR "\-1e\-10 truncated"
-       _ int64 = -1e-100     // ERROR "\-1e\-100 truncated"
-       _ int64 = -1e-1000    // ERROR "\-1e\-1000 truncated"
-       _ int64 = -1e-10000   // ERROR "\-1e\-10000 truncated"
-       _ int64 = -1e-100000  // ERROR "\-1e\-100000 truncated"
-       _ int64 = -1e-1000000 // ERROR "\-1e\-1000000 truncated"
+       _ int64 = -1e-1       // ERROR "\-0\.1 truncated|.* truncated to int64"
+       _ int64 = -1e-10      // ERROR "\-1e\-10 truncated|.* truncated to int64"
+       _ int64 = -1e-100     // ERROR "\-1e\-100 truncated|.* truncated to int64"
+       _ int64 = -1e-1000    // ERROR "\-1e\-1000 truncated|.* truncated to int64"
+       _ int64 = -1e-10000   // ERROR "\-1e\-10000 truncated|.* truncated to int64"
+       _ int64 = -1e-100000  // ERROR "\-1e\-100000 truncated|.* truncated to int64"
+       _ int64 = -1e-1000000 // ERROR "\-1e\-1000000 truncated|.* truncated to int64"
 )
 
 const (
-       _ int64 = 1.23456789e10000000 // ERROR "integer too large"
-       _ int64 = 1.23456789e1000000  // ERROR "integer too large"
-       _ int64 = 1.23456789e100000   // ERROR "integer too large"
-       _ int64 = 1.23456789e10000    // ERROR "integer too large"
-       _ int64 = 1.23456789e1000     // ERROR "integer too large"
-       _ int64 = 1.23456789e100      // ERROR "12345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows"
+       _ int64 = 1.23456789e10000000 // ERROR "integer too large|truncated to int64"
+       _ int64 = 1.23456789e1000000  // ERROR "integer too large|truncated to int64"
+       _ int64 = 1.23456789e100000   // ERROR "integer too large|truncated to int64"
+       _ int64 = 1.23456789e10000    // ERROR "integer too large|truncated to int64"
+       _ int64 = 1.23456789e1000     // ERROR "integer too large|truncated to int64"
+       _ int64 = 1.23456789e100      // ERROR "12345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows|truncated to int64"
        _ int64 = 1.23456789e10
-       _ int64 = 1.23456789e1        // ERROR "12\.3457 truncated"
-       _ int64 = 1.23456789e0        // ERROR "1\.23457 truncated"
-       _ int64 = 1.23456789e-1       // ERROR "0\.123457 truncated"
-       _ int64 = 1.23456789e-10      // ERROR "1\.23457e\-10 truncated"
-       _ int64 = 1.23456789e-100     // ERROR "1\.23457e\-100 truncated"
-       _ int64 = 1.23456789e-1000    // ERROR "1\.23457e\-1000 truncated"
-       _ int64 = 1.23456789e-10000   // ERROR "1\.23457e\-10000 truncated"
-       _ int64 = 1.23456789e-100000  // ERROR "1\.23457e\-100000 truncated"
-       _ int64 = 1.23456789e-1000000 // ERROR "1\.23457e\-1000000 truncated"
+       _ int64 = 1.23456789e1        // ERROR "12\.3457 truncated|.* truncated to int64"
+       _ int64 = 1.23456789e0        // ERROR "1\.23457 truncated|.* truncated to int64"
+       _ int64 = 1.23456789e-1       // ERROR "0\.123457 truncated|.* truncated to int64"
+       _ int64 = 1.23456789e-10      // ERROR "1\.23457e\-10 truncated|.* truncated to int64"
+       _ int64 = 1.23456789e-100     // ERROR "1\.23457e\-100 truncated|.* truncated to int64"
+       _ int64 = 1.23456789e-1000    // ERROR "1\.23457e\-1000 truncated|.* truncated to int64"
+       _ int64 = 1.23456789e-10000   // ERROR "1\.23457e\-10000 truncated|.* truncated to int64"
+       _ int64 = 1.23456789e-100000  // ERROR "1\.23457e\-100000 truncated|.* truncated to int64"
+       _ int64 = 1.23456789e-1000000 // ERROR "1\.23457e\-1000000 truncated|.* truncated to int64"
 )
 
 const (
-       _ int64 = -1.23456789e10000000 // ERROR "integer too large"
-       _ int64 = -1.23456789e1000000  // ERROR "integer too large"
-       _ int64 = -1.23456789e100000   // ERROR "integer too large"
-       _ int64 = -1.23456789e10000    // ERROR "integer too large"
-       _ int64 = -1.23456789e1000     // ERROR "integer too large"
-       _ int64 = -1.23456789e100      // ERROR "\-12345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows"
+       _ int64 = -1.23456789e10000000 // ERROR "integer too large|truncated to int64"
+       _ int64 = -1.23456789e1000000  // ERROR "integer too large|truncated to int64"
+       _ int64 = -1.23456789e100000   // ERROR "integer too large|truncated to int64"
+       _ int64 = -1.23456789e10000    // ERROR "integer too large|truncated to int64"
+       _ int64 = -1.23456789e1000     // ERROR "integer too large|truncated to int64"
+       _ int64 = -1.23456789e100      // ERROR "\-12345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 overflows|truncated to int64"
        _ int64 = -1.23456789e10
-       _ int64 = -1.23456789e1        // ERROR "\-12\.3457 truncated"
-       _ int64 = -1.23456789e0        // ERROR "\-1\.23457 truncated"
-       _ int64 = -1.23456789e-1       // ERROR "\-0\.123457 truncated"
-       _ int64 = -1.23456789e-10      // ERROR "\-1\.23457e\-10 truncated"
-       _ int64 = -1.23456789e-100     // ERROR "\-1\.23457e\-100 truncated"
-       _ int64 = -1.23456789e-1000    // ERROR "\-1\.23457e\-1000 truncated"
-       _ int64 = -1.23456789e-10000   // ERROR "\-1\.23457e\-10000 truncated"
-       _ int64 = -1.23456789e-100000  // ERROR "\-1\.23457e\-100000 truncated"
-       _ int64 = -1.23456789e-1000000 // ERROR "\-1\.23457e\-1000000 truncated"
+       _ int64 = -1.23456789e1        // ERROR "\-12\.3457 truncated|.* truncated to int64"
+       _ int64 = -1.23456789e0        // ERROR "\-1\.23457 truncated|.* truncated to int64"
+       _ int64 = -1.23456789e-1       // ERROR "\-0\.123457 truncated|.* truncated to int64"
+       _ int64 = -1.23456789e-10      // ERROR "\-1\.23457e\-10 truncated|.* truncated to int64"
+       _ int64 = -1.23456789e-100     // ERROR "\-1\.23457e\-100 truncated|.* truncated to int64"
+       _ int64 = -1.23456789e-1000    // ERROR "\-1\.23457e\-1000 truncated|.* truncated to int64"
+       _ int64 = -1.23456789e-10000   // ERROR "\-1\.23457e\-10000 truncated|.* truncated to int64"
+       _ int64 = -1.23456789e-100000  // ERROR "\-1\.23457e\-100000 truncated|.* truncated to int64"
+       _ int64 = -1.23456789e-1000000 // ERROR "\-1\.23457e\-1000000 truncated|.* truncated to int64"
 )
index 38308cd75c94e298412de4f87a3095d4c49b3032..a066d2664ffcf9f3ebccd6aeab037f5c39fe45e0 100644 (file)
@@ -15,5 +15,7 @@ type T struct{}
 
 func main() {
        t := T{X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1} // ERROR "unknown field 'X' in struct literal of type T|unknown field .*X.* in .*T.*"
-       var s string = 1 // ERROR "cannot use 1|incompatible type"
+       _ = t
+       var s string = 1 // ERROR "cannot use 1|incompatible type|cannot convert"
+       _ = s
 }
index e1149c3f9d06d865a18ac574fa3adcaaf884425c..0791819907411433a7f15f6a9c3b6f3f4a24baa7 100644 (file)
@@ -30,4 +30,4 @@ type C struct {
 var _ = C.F // ERROR "ambiguous"
 var _ = C.G // ERROR "ambiguous"
 var _ = C.H // ERROR "ambiguous"
-var _ = C.I // ERROR "no method .*I.*"
+var _ = C.I // ERROR "no method .*I.*|C.I undefined"
index 9b30fd271505b58c06bd56a58f001fe06ecc9c14..e5c8235849b96e2715a6cb41ed6c9b415421e3fa 100644 (file)
@@ -10,5 +10,5 @@ package main
 
 import "unsafe"
 
-type s struct { unsafe.Pointer } // ERROR "embedded type cannot be a pointer|embedded type may not be a pointer"
+type s struct { unsafe.Pointer } // ERROR "embedded type cannot be a pointer|embedded type may not be a pointer||embedded field type cannot be unsafe.Pointer"
 type s1 struct { p unsafe.Pointer }
index e58047e411caa50f2864992c7215af89b600f5f4..b6c3d96da6ecf48b09a44c743c0a041648695225 100644 (file)
@@ -8,10 +8,10 @@ package main
 
 func main() {
        type name string
-       _ = []byte("abc", "def", 12)    // ERROR "too many arguments to conversion to \[\]byte: \(\[\]byte\)\(.abc., .def., 12\)"
-       _ = string("a", "b", nil)       // ERROR "too many arguments to conversion to string: string\(.a., .b., nil\)"
-       _ = []byte()                    // ERROR "missing argument to conversion to \[\]byte: \(\[\]byte\)\(\)"
-       _ = string()                    // ERROR "missing argument to conversion to string: string\(\)"
-       _ = name("a", 1, 3.3)           // ERROR "too many arguments to conversion to name: name\(.a., 1, 3.3\)"
-       _ = map[string]string(nil, nil) // ERROR "too many arguments to conversion to map\[string\]string: \(map\[string\]string\)\(nil, nil\)"
+       _ = []byte("abc", "def", 12)    // ERROR "too many arguments (to conversion to \[\]byte: \(\[\]byte\)\(.abc., .def., 12\))?"
+       _ = string("a", "b", nil)       // ERROR "too many arguments (to conversion to string: string\(.a., .b., nil\))?"
+       _ = []byte()                    // ERROR "missing argument (to conversion to \[\]byte: \(\[\]byte\)\(\))?"
+       _ = string()                    // ERROR "missing argument (to conversion to string: string\(\))?"
+       _ = name("a", 1, 3.3)           // ERROR "too many arguments (to conversion to name: name\(.a., 1, 3.3\))?"
+       _ = map[string]string(nil, nil) // ERROR "too many arguments (to conversion to map\[string\]string: \(map\[string\]string\)\(nil, nil\))?"
 }
index 94369f93450f29b46d36da42b8adf53f4fe557c6..09f906ae582c19e929524ad968f27c768268fc42 100644 (file)
@@ -8,11 +8,11 @@ package p
 
 func f(e interface{}) {
        switch e.(type) {
-       case nil, nil: // ERROR "multiple nil cases in type switch|duplicate type in switch"
+       case nil, nil: // ERROR "multiple nil cases in type switch|duplicate type in switch|duplicate case nil in type switch"
        }
 
        switch e.(type) {
        case nil:
-       case nil: // ERROR "multiple nil cases in type switch|duplicate type in switch"
+       case nil: // ERROR "multiple nil cases in type switch|duplicate type in switch|duplicate case nil in type switch"
        }
 }
index 704b6b15a61aac9b2f984a034ef37bf21391bd29..77baa1f4e8c9fdb8196d68eb8154413bba5b0f0e 100644 (file)
@@ -7,12 +7,12 @@
 package p
 
 var a []int = []int{1: 1}
-var b []int = []int{-1: 1} // ERROR "must be non-negative integer constant|index expression is negative"
+var b []int = []int{-1: 1} // ERROR "must be non-negative integer constant|index expression is negative|must not be negative"
 
 var c []int = []int{2.0: 2}
-var d []int = []int{-2.0: 2} // ERROR "must be non-negative integer constant|index expression is negative"
+var d []int = []int{-2.0: 2} // ERROR "must be non-negative integer constant|index expression is negative|must not be negative"
 
 var e []int = []int{3 + 0i: 3}
-var f []int = []int{3i: 3} // ERROR "truncated to integer|index expression is not integer constant"
+var f []int = []int{3i: 3} // ERROR "truncated to integer|index expression is not integer constant|truncated to int"
 
-var g []int = []int{"a": 4} // ERROR "must be non-negative integer constant|index expression is not integer constant"
+var g []int = []int{"a": 4} // ERROR "must be non-negative integer constant|index expression is not integer constant|cannot convert"
index 9ee3387e9693a0fe4022d502612401f9d003cae7..1007d701dec34a4944385dc1362e49b00e9b0630 100644 (file)
@@ -12,19 +12,19 @@ var sink []byte
 
 func main() {
        sink = make([]byte, 1.0)
-       sink = make([]byte, float32(1.0)) // ERROR "non-integer.*len"
-       sink = make([]byte, float64(1.0)) // ERROR "non-integer.*len"
+       sink = make([]byte, float32(1.0)) // ERROR "non-integer.*len|must be integer"
+       sink = make([]byte, float64(1.0)) // ERROR "non-integer.*len|must be integer"
 
        sink = make([]byte, 0, 1.0)
-       sink = make([]byte, 0, float32(1.0)) // ERROR "non-integer.*cap"
-       sink = make([]byte, 0, float64(1.0)) // ERROR "non-integer.*cap"
+       sink = make([]byte, 0, float32(1.0)) // ERROR "non-integer.*cap|must be integer"
+       sink = make([]byte, 0, float64(1.0)) // ERROR "non-integer.*cap|must be integer"
 
        sink = make([]byte, 1+0i)
-       sink = make([]byte, complex64(1+0i))  // ERROR "non-integer.*len"
-       sink = make([]byte, complex128(1+0i)) // ERROR "non-integer.*len"
+       sink = make([]byte, complex64(1+0i))  // ERROR "non-integer.*len|must be integer"
+       sink = make([]byte, complex128(1+0i)) // ERROR "non-integer.*len|must be integer"
 
        sink = make([]byte, 0, 1+0i)
-       sink = make([]byte, 0, complex64(1+0i))  // ERROR "non-integer.*cap"
-       sink = make([]byte, 0, complex128(1+0i)) // ERROR "non-integer.*cap"
+       sink = make([]byte, 0, complex64(1+0i))  // ERROR "non-integer.*cap|must be integer"
+       sink = make([]byte, 0, complex128(1+0i)) // ERROR "non-integer.*cap|must be integer"
 
 }
index 0e3a14ef7c4faa6a398a6d4f598bd762e068a3d9..ed5312fa2165fe542db727b8174e3e7aa0581f34 100644 (file)
@@ -11,7 +11,7 @@
 
 package p
 
-type F func(b T)  // ERROR "T is not a type|expected type"
+type F func(b T)  // ERROR "T .*is not a type|expected type"
 
 func T(fn F) {
     func() {
index 053a337867997cd9df9c03183c2e9925b20f6de4..e0640ed2ee48b408b4a5e6f72c0c1195425e126f 100644 (file)
@@ -10,5 +10,5 @@ type A interface {
        // TODO(mdempsky): This should be an error, but this error is
        // nonsense. The error should actually mention that there's a
        // type loop.
-       Fn(A.Fn) // ERROR "type A has no method Fn"
+       Fn(A.Fn) // ERROR "type A has no method Fn|A.Fn undefined"
 }
index 71365e10dd3d8089f8e6c5f536352bf4bc8cdd24..77cac3ee16a230119167bc51d2806225b87f3d48 100644 (file)
@@ -9,11 +9,11 @@ package p
 func g() {}
 
 func f() {
-       g()[:] // ERROR "g.. used as value|attempt to slice object that is not"
+       g()[:] // ERROR "g.* used as value|attempt to slice object that is not"
 }
 
 func g2() ([]byte, []byte) { return nil, nil }
 
 func f2() {
-       g2()[:] // ERROR "multiple-value g2.. in single-value context|attempt to slice object that is not"
+       g2()[:] // ERROR "multiple-value g2.. in single-value context|attempt to slice object that is not|2\-valued g"
 }
index 4c2c19ec9d9d4ce63457c29b07b559c236305daf..ee0d340aa3c50ac65bd6e0f21d7e505d8255df33 100644 (file)
@@ -22,13 +22,13 @@ func ok() {
 
 var (
        y = T{"stare"}
-       w = T{_: "look"} // ERROR "invalid field name _ in struct initializer|expected struct field name"
+       w = T{_: "look"} // ERROR "invalid field name _ in struct initializer|expected struct field name|unknown field '_' in struct literal of type T"
        _ = T{"page"}
-       _ = T{_: "out"} // ERROR "invalid field name _ in struct initializer|expected struct field name"
+       _ = T{_: "out"} // ERROR "invalid field name _ in struct initializer|expected struct field name|unknown field '_' in struct literal of type T"
 )
 
 func bad() {
-       var z = T{_: "verse"} // ERROR "invalid field name _ in struct initializer|expected struct field name"
+       var z = T{_: "verse"} // ERROR "invalid field name _ in struct initializer|expected struct field name|unknown field '_' in struct literal of type T"
        _ = z
-       _ = T{_: "itinerary"} // ERROR "invalid field name _ in struct initializer|expected struct field name"
+       _ = T{_: "itinerary"} // ERROR "invalid field name _ in struct initializer|expected struct field name|unknown field '_' in struct literal of type T"
 }
index 4afc0ca8330501e6fbed9529c5bcc76c57e03c9d..32ed30fd2bae2a068881151aec0a2f566a5c32ad 100644 (file)
@@ -11,4 +11,4 @@ func f() bool {
        } else {
                return true
        }
-} // ERROR "missing return at end of function"
+} // ERROR "missing return( at end of function)?"
index 3d83cf3a12c3dd287b1fc8e9c42309e108fd3c67..57cdc93ef6629ee611226353c17e830a87a30b28 100644 (file)
@@ -11,7 +11,7 @@ type T struct {
 }
 
 func a() {
-       _ = T // ERROR "type T is not an expression|invalid use of type"
+       _ = T // ERROR "type T is not an expression|invalid use of type|not an expression"
 }
 
 func b() {
index 3233469e3930de741a8d6d4dc52f3d18879a5482..752cfc6bf602d08fd91acd78fa8af812f925349e 100644 (file)
@@ -8,8 +8,8 @@
 
 package issue19947
 
-var _ = float32(1) * 1e200 // ERROR "constant 1e\+200 overflows float32"
-var _ = float64(1) * 1e500 // ERROR "constant 1e\+500 overflows float64"
+var _ = float32(1) * 1e200 // ERROR "constant 1e\+200 overflows float32|1e200 .* overflows float32"
+var _ = float64(1) * 1e500 // ERROR "constant 1e\+500 overflows float64|1e500 .* overflows float64"
 
-var _ = complex64(1) * 1e200  // ERROR "constant 1e\+200 overflows complex64"
-var _ = complex128(1) * 1e500 // ERROR "constant 1e\+500 overflows complex128"
+var _ = complex64(1) * 1e200  // ERROR "constant 1e\+200 overflows complex64|1e200 .* overflows complex64"
+var _ = complex128(1) * 1e500 // ERROR "constant 1e\+500 overflows complex128|1e500 .* overflows complex128"
index 9065868d7f2ba1c3690e860efc4bc754671f77a7..ee60cabd6f538ca4f435beda1de29e0ea563396c 100644 (file)
@@ -10,7 +10,7 @@
 package p
 
 func F() {
-       switch t := nil.(type) { // ERROR "cannot type switch on non-interface value"
+       switch t := nil.(type) { // ERROR "cannot type switch on non-interface value|not an interface"
        default:
                _ = t
        }
@@ -19,7 +19,7 @@ func F() {
 const x = 1
 
 func G() {
-       switch t := x.(type) { // ERROR "cannot type switch on non-interface value|declared but not used"
+       switch t := x.(type) { // ERROR "cannot type switch on non-interface value|declared but not used|not an interface"
        default:
        }
 }
index 1d9a745ab47feda357827b77eb8b41494b41fcf1..71f34bba57cbf4d17076a75a94045accc04b633e 100644 (file)
@@ -11,7 +11,7 @@ package p
 // 1
 var f byte
 
-var f interface{} // ERROR "issue20415.go:12: previous declaration|redefinition"
+var f interface{} // ERROR "issue20415.go:12: previous declaration|redefinition|f redeclared"
 
 func _(f int) {
 }
@@ -22,7 +22,7 @@ var g byte
 func _(g int) {
 }
 
-var g interface{} // ERROR "issue20415.go:20: previous declaration|redefinition"
+var g interface{} // ERROR "issue20415.go:20: previous declaration|redefinition|g redeclared"
 
 // 3
 func _(h int) {
@@ -30,4 +30,4 @@ func _(h int) {
 
 var h byte
 
-var h interface{} // ERROR "issue20415.go:31: previous declaration|redefinition"
+var h interface{} // ERROR "issue20415.go:31: previous declaration|redefinition|h redeclared"
index de2d3ad16a854980338b7c63330123fcfc64b752..2ca1f43d02c6fb2881e8b2077e19b65d54d8958c 100644 (file)
@@ -9,7 +9,7 @@ package p
 // Verify that the compiler complains even if the array
 // has length 0.
 var a [0]int
-var _ = a[2:] // ERROR "invalid slice index 2|array index out of bounds"
+var _ = a[2:] // ERROR "invalid slice index 2|array index out of bounds|index 2 out of bounds"
 
 var b [1]int
-var _ = b[2:] // ERROR "invalid slice index 2|array index out of bounds"
+var _ = b[2:] // ERROR "invalid slice index 2|array index out of bounds|index 2 out of bounds"
index 706b44941c0361046cd8a6cf8222adfda6f9f192..75dc28540358ac08541baccdd9d1ce1003ce2a9f 100644 (file)
@@ -14,5 +14,5 @@ func (f *Foo) Call(cb func(*Foo)) {
 
 func main() {
        f := &Foo{}
-       f.Call(func(f) {}) // ERROR "f is not a type"
+       f.Call(func(f) {}) // ERROR "f .*is not a type"
 }
index 2ac31ef0c75782f7e6532ba63e2cd9310948185b..e13e470a01eae71c1a2e90001c05b9c0ba94b24c 100644 (file)
@@ -17,4 +17,5 @@ func main() {
        }
        i2 := &it{floats: false} // ERROR "(but does have Floats)|unknown field|declared but not used"
        _ = &it{InneR: "foo"}    // ERROR "(but does have inner)|unknown field"
+       _ = i2
 }
index dc86c97fe570655287ac2e0a2b49f76405e76970..9483c9cab0ab1c7b6b401531dea514cc18402bf9 100644 (file)
@@ -11,8 +11,9 @@ package main
 
 func F() {
        slice := []int{1, 2, 3}
+       _ = slice
        len := int(2)
-       println(len(slice)) // ERROR "cannot call non-function len .type int., declared at LINE-1|expected function"
+       println(len(slice)) // ERROR "cannot call non-function len .type int., declared at LINE-1|expected function|cannot call non-function len"
        const iota = 1
-       println(iota(slice)) // ERROR "cannot call non-function iota .type int., declared at LINE-1|expected function"
+       println(iota(slice)) // ERROR "cannot call non-function iota .type int., declared at LINE-1|expected function|cannot call non-function iota"
 }
index 415556f300ca38f326dfb0863e2624b2c57a6b32..853b19b92f38fe1216c61a2aa91baabb3da496fa 100644 (file)
@@ -8,4 +8,4 @@
 
 package p
 
-var a [len(a)]int // ERROR "\[len\(a\)\]int"
+var a [len(a)]int // ERROR "\[len\(a\)\]int|initialization loop"
index 7c17a98d32d0636e770957e95bd7a12609533ced..9130e8dd1621ec459fc5fd1c3ebec99c914bd2e4 100644 (file)
@@ -21,7 +21,7 @@ type t3 struct {
 }
 
 var (
-       _ = t2{t1f1: 600} // ERROR "cannot use promoted field t1.t1f1 in struct literal of type t2"
-       _ = t3{t1f2: 800} // ERROR "cannot use promoted field t2.t1.t1f2 in struct literal of type t3"
-       _ = t3{t2f1: 900} // ERROR "cannot use promoted field t2.t2f1 in struct literal of type t3"
+       _ = t2{t1f1: 600} // ERROR "cannot use promoted field t1.t1f1 in struct literal of type t2|unknown field"
+       _ = t3{t1f2: 800} // ERROR "cannot use promoted field t2.t1.t1f2 in struct literal of type t3|unknown field"
+       _ = t3{t2f1: 900} // ERROR "cannot use promoted field t2.t2f1 in struct literal of type t3|unknown field"
 )
index 067a8f1638c26c4ae33fe5c116d2c0c0c14d8fdf..c53415f7b9146547ae50ea8a5e755d87b6cea7a5 100644 (file)
@@ -11,6 +11,6 @@ type I1 = interface {
 }
 
 // BAD: type loop should mention I1; see also #41669
-type I2 interface { // GC_ERROR "invalid recursive type I2\n\tLINE: I2 refers to\n\tLINE: I2$"
+type I2 interface { // GC_ERROR "invalid recursive type I2\n\tLINE: I2 refers to\n\tLINE: I2$|invalid recursive type I2"
        I1 // GCCGO_ERROR "invalid recursive interface"
 }
index d0e5e23fa90840208aa2fa069a3e93f3aff6362b..2805998cca57bb5430cf3fb25cb4085761a98723 100644 (file)
@@ -11,5 +11,6 @@ package p
 
 func f(i interface{}) {
        if x, ok := i.(type); ok { // ERROR "outside type switch"
+               _ = x
        }
 }
index 936b9f8ff5cd65e99ff2ea5e2f16f228ed226c93..5599a83dd02111d87120058c682f0e988dde0991 100644 (file)
@@ -9,13 +9,13 @@ package main
 import "net/http"
 
 var s = http.Server{}
-var _ = s.doneChan                  // ERROR "s.doneChan undefined .cannot refer to unexported field or method doneChan.$|unexported field or method"
+var _ = s.doneChan                  // ERROR "s.doneChan undefined .cannot refer to unexported field or method doneChan.$|unexported field or method|s.doneChan undefined"
 var _ = s.DoneChan                  // ERROR "s.DoneChan undefined .type http.Server has no field or method DoneChan.$|undefined field or method"
-var _ = http.Server{tlsConfig: nil} // ERROR "unknown field 'tlsConfig' in struct literal.+ .but does have TLSConfig.$|unknown field .?tlsConfig.? in .?http.Server"
+var _ = http.Server{tlsConfig: nil} // ERROR "unknown field 'tlsConfig' in struct literal.+ .but does have TLSConfig.$|unknown field .?tlsConfig.? in .?http.Server|unknown field"
 var _ = http.Server{DoneChan: nil}  // ERROR "unknown field 'DoneChan' in struct literal of type http.Server$|unknown field .?DoneChan.? in .?http.Server"
 
 type foo struct {
        bar int
 }
 
-var _ = &foo{bAr: 10} // ERROR "unknown field 'bAr' in struct literal.+ .but does have bar.$|unknown field .?bAr.? in .?foo"
+var _ = &foo{bAr: 10} // ERROR "unknown field 'bAr' in struct literal.+ .but does have bar.$|unknown field .?bAr.? in .?foo|unknown field"
index 87c0293661f8ad8dadf1aa3f15ad8b2007d6c674..d5210e87b0f5af9d9183dbd7335f6ece002e6689 100644 (file)
@@ -6,14 +6,13 @@
 
 package p
 
-var x int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context"
+var x int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|3\-valued"
 
 func f() {
-       var _ int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context"
-       var a int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context"
-       a = three()         // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context"
-       b := three()        // ERROR "assignment mismatch: 1 variable but three returns 3 values|single variable set to multiple-value|multiple-value function call in single-value context"
-
+       var _ int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|3\-valued"
+       var a int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|3\-valued"
+       a = three()         // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|cannot assign"
+       b := three()        // ERROR "assignment mismatch: 1 variable but three returns 3 values|single variable set to multiple-value|multiple-value function call in single-value context|cannot initialize"
        _, _ = a, b
 }
 
index af5c7a10d9b0161a14022b74816745c5b1d05506..82771457698599474aafb55fff97fa0e8d22a870 100644 (file)
@@ -6,9 +6,9 @@
 
 package main
 
-var a = twoResults()       // ERROR "assignment mismatch: 1 variable but twoResults returns 2 values"
-var b, c, d = twoResults() // ERROR "assignment mismatch: 3 variables but twoResults returns 2 values"
-var e, f = oneResult()     // ERROR "assignment mismatch: 2 variables but oneResult returns 1 values"
+var a = twoResults()       // ERROR "assignment mismatch: 1 variable but twoResults returns 2 values|2\-valued"
+var b, c, d = twoResults() // ERROR "assignment mismatch: 3 variables but twoResults returns 2 values|cannot initialize"
+var e, f = oneResult()     // ERROR "assignment mismatch: 2 variables but oneResult returns 1 values|cannot initialize"
 
 func twoResults() (int, int) {
        return 1, 2
index dfac8d01554737f8ebdc93f51b522a562479a272..f6954eda42e21da97c087fa1006cbd62dace61d8 100644 (file)
@@ -11,5 +11,5 @@ package p
 import "unsafe"
 
 func f() {
-       _ = complex(1<<uintptr(unsafe.Pointer(nil)), 0) // ERROR "invalid operation: .*shift of type float64.*|non-integer type for left operand of shift"
+       _ = complex(1<<uintptr(unsafe.Pointer(nil)), 0) // ERROR "invalid operation: .*shift of type float64.*|non-integer type for left operand of shift|shifted operand .* must be integer"
 }
index 2acfe39177a04d68b98eeb3ac772760beaab058c..ca7ba14b1c63321db69a0b12a1197ddb6baf0412 100644 (file)
@@ -6,13 +6,13 @@
 
 package p
 
-func f(a, b, c, d ...int)       {} // ERROR "non-final parameter a|only permits one name"
-func g(a ...int, b ...int)      {} // ERROR "non-final parameter a|must be last parameter"
-func h(...int, ...int, float32) {} // ERROR "non-final parameter|must be last parameter"
+func f(a, b, c, d ...int)       {} // ERROR "non-final parameter a|only permits one name|can only use ... with final parameter"
+func g(a ...int, b ...int)      {} // ERROR "non-final parameter a|must be last parameter|can only use ... with final parameter"
+func h(...int, ...int, float32) {} // ERROR "non-final parameter|must be last parameter|can only use ... with final parameter"
 
-type a func(...float32, ...interface{}) // ERROR "non-final parameter|must be last parameter"
+type a func(...float32, ...interface{}) // ERROR "non-final parameter|must be last parameter|can only use ... with final parameter"
 type b interface {
-       f(...int, ...int)                // ERROR "non-final parameter|must be last parameter"
-       g(a ...int, b ...int, c float32) // ERROR "non-final parameter a|must be last parameter"
+       f(...int, ...int)                // ERROR "non-final parameter|must be last parameter|can only use ... with final parameter"
+       g(a ...int, b ...int, c float32) // ERROR "non-final parameter a|must be last parameter|can only use ... with final parameter"
        valid(...int)
 }
index d2ac4cfbfa7a06bb598fb4b7e20d9aa4799a61eb..512355a443a69c352557a6eafd971d317fa5de0e 100644 (file)
@@ -7,6 +7,7 @@
 package main
 
 func main() {
-       var c, d = 1, 2, 3 // ERROR "assignment mismatch: 2 variables but 3 values|wrong number of initializations"
-       var e, f, g = 1, 2 // ERROR "assignment mismatch: 3 variables but 2 values|wrong number of initializations"
+       var c, d = 1, 2, 3 // ERROR "assignment mismatch: 2 variables but 3 values|wrong number of initializations|extra init expr"
+       var e, f, g = 1, 2 // ERROR "assignment mismatch: 3 variables but 2 values|wrong number of initializations|missing init expr"
+       _, _, _, _ = c, d, e, f
 }
index 3ad9c8c8d90c0c32479a5d48b1bf72845df19171..e2aec63a52931debc54d70618b52687f83f61d41 100644 (file)
@@ -7,8 +7,9 @@
 package main
 
 func main() {
-       var a, b = 1    // ERROR "assignment mismatch: 2 variables but 1 values|wrong number of initializations"
-       _ = 1, 2        // ERROR "assignment mismatch: 1 variables but 2 values|number of variables does not match"
-       c, d := 1       // ERROR "assignment mismatch: 2 variables but 1 values|wrong number of initializations"
-       e, f := 1, 2, 3 // ERROR "assignment mismatch: 2 variables but 3 values|wrong number of initializations"
+       var a, b = 1    // ERROR "assignment mismatch: 2 variables but 1 values|wrong number of initializations|cannot initialize"
+       _ = 1, 2        // ERROR "assignment mismatch: 1 variables but 2 values|number of variables does not match|cannot assign"
+       c, d := 1       // ERROR "assignment mismatch: 2 variables but 1 values|wrong number of initializations|cannot initialize"
+       e, f := 1, 2, 3 // ERROR "assignment mismatch: 2 variables but 3 values|wrong number of initializations|cannot initialize"
+       _, _, _, _ = c, d, e, f
 }
index 5d8381c244e3e663edd36c58b03e6293cc9ddd40..f6cd45573c5e9e52e9f480e3dd6a2c2b9cfba3ff 100644 (file)
@@ -10,5 +10,5 @@ package p
 
 var s = []string{
        1: "dup",
-       1: "dup", // ERROR "duplicate index in slice literal: 1|duplicate value for index 1"
+       1: "dup", // ERROR "duplicate index in slice literal: 1|duplicate value for index 1|duplicate index 1"
 }
index 11edef7f2532d5078a2864f69e065c6e3b27c9d8..c0707ef6dc7be603a6f2b141cdf0f6715764a9b3 100644 (file)
@@ -13,5 +13,5 @@ const (
        _ = int(complex64(int(0)))
        _ = float64(complex128(float64(0)))
 
-       _ = int8(complex128(1000)) // ERROR "overflow"
+       _ = int8(complex128(1000)) // ERROR "overflow|cannot convert"
 )
index 7d4283b8453ddfc0d5e2dc9bf61b3876ab2a60b0..3a84a5622bc4d44060ddaf3da6bc11db1b3ec712 100644 (file)
@@ -10,7 +10,7 @@ type t struct{ x int }
 
 func f1() {
        t{}.M()     // ERROR "t{}.M undefined \(type t has no field or method M\)|undefined field or method .*M"
-       t{x: 1}.M() // ERROR "t{...}.M undefined \(type t has no field or method M\)|undefined field or method .*M"
+       t{x: 1}.M() // ERROR "t{...}.M undefined \(type t has no field or method M\)|undefined field or method .*M|no field or method M"
 }
 
 func f2() (*t, error) {
index 628c222685efbb34839cc5a9a71be11d4994c0fd..f0851878ec7268bfc12ab2bb936eb09179981061 100644 (file)
@@ -18,6 +18,6 @@ var _ = map[string]string{
 var _ = []string{
        "foo",
        "bar",
-       20, // ERROR "cannot use|incompatible type"
+       20, // ERROR "cannot use|incompatible type|cannot convert"
 }
 
index 200290a081d1fa40c50bf97242f2ac6ca3dd9da8..bf97c9e4494548e1538182b2ae15e9181590d387 100644 (file)
@@ -10,9 +10,9 @@ type T []int
 
 func main() {
        _ = make(T, -1)    // ERROR "negative"
-       _ = make(T, 0.5)   // ERROR "constant 0.5 truncated to integer|non-integer len argument"
+       _ = make(T, 0.5)   // ERROR "constant 0.5 truncated to integer|non-integer len argument|truncated to int"
        _ = make(T, 1.0)   // ok
-       _ = make(T, 1<<63) // ERROR "len argument too large"
-       _ = make(T, 0, -1) // ERROR "negative cap"
-       _ = make(T, 10, 0) // ERROR "len larger than cap"
+       _ = make(T, 1<<63) // ERROR "len argument too large|overflows int"
+       _ = make(T, 0, -1) // ERROR "negative cap|must not be negative"
+       _ = make(T, 10, 0) // ERROR "len larger than cap|length and capacity swapped"
 }
index 82dca34820a37726d102fe70e13bbae8afbce244..3ec23a0dfe08ba973230b633a1e59058127d6e35 100644 (file)
@@ -13,8 +13,8 @@ type s struct {
 func f() {
        var x *s
 
-       _ = x == nil || len(x.slice) // ERROR "invalid operation: .+ \(operator \|\| not defined on int\)|incompatible types"
-       _ = len(x.slice) || x == nil // ERROR "invalid operation: .+ \(operator \|\| not defined on int\)|incompatible types"
-       _ = x == nil && len(x.slice) // ERROR "invalid operation: .+ \(operator && not defined on int\)|incompatible types"
-       _ = len(x.slice) && x == nil // ERROR "invalid operation: .+ \(operator && not defined on int\)|incompatible types"
+       _ = x == nil || len(x.slice) // ERROR "invalid operation: .+ \(operator \|\| not defined on int\)|incompatible types|cannot convert"
+       _ = len(x.slice) || x == nil // ERROR "invalid operation: .+ \(operator \|\| not defined on int\)|incompatible types|cannot convert"
+       _ = x == nil && len(x.slice) // ERROR "invalid operation: .+ \(operator && not defined on int\)|incompatible types|cannot convert"
+       _ = len(x.slice) && x == nil // ERROR "invalid operation: .+ \(operator && not defined on int\)|incompatible types|cannot convert"
 }
index be9fc7434a7d45e28827d9b18998811a1fef4e23..7201591f3f3c851445c7d3d007739acf60359bfa 100644 (file)
@@ -7,28 +7,28 @@
 package main
 
 func foo() (int, int) {
-       return 2.3 // ERROR "not enough arguments to return\n\thave \(number\)\n\twant \(int, int\)|not enough arguments to return"
+       return 2.3 // ERROR "not enough arguments to return\n\thave \(number\)\n\twant \(int, int\)|not enough arguments to return|wrong number of return values"
 }
 
 func foo2() {
-       return int(2), 2 // ERROR "too many arguments to return\n\thave \(int, number\)\n\twant \(\)|return with value in function with no return type"
+       return int(2), 2 // ERROR "too many arguments to return\n\thave \(int, number\)\n\twant \(\)|return with value in function with no return type|no result values expected"
 }
 
 func foo3(v int) (a, b, c, d int) {
        if v >= 0 {
-               return 1 // ERROR "not enough arguments to return\n\thave \(number\)\n\twant \(int, int, int, int\)|not enough arguments to return"
+               return 1 // ERROR "not enough arguments to return\n\thave \(number\)\n\twant \(int, int, int, int\)|not enough arguments to return|wrong number of return values"
        }
-       return 2, 3 // ERROR "not enough arguments to return\n\thave \(number, number\)\n\twant \(int, int, int, int\)|not enough arguments to return"
+       return 2, 3 // ERROR "not enough arguments to return\n\thave \(number, number\)\n\twant \(int, int, int, int\)|not enough arguments to return|wrong number of return values"
 }
 
 func foo4(name string) (string, int) {
        switch name {
        case "cow":
-               return "moo" // ERROR "not enough arguments to return\n\thave \(string\)\n\twant \(string, int\)|not enough arguments to return"
+               return "moo" // ERROR "not enough arguments to return\n\thave \(string\)\n\twant \(string, int\)|not enough arguments to return|wrong number of return values"
        case "dog":
-               return "dog", 10, true // ERROR "too many arguments to return\n\thave \(string, number, bool\)\n\twant \(string, int\)|too many values in return statement"
+               return "dog", 10, true // ERROR "too many arguments to return\n\thave \(string, number, bool\)\n\twant \(string, int\)|too many values in return statement|wrong number of return values"
        case "fish":
-               return "" // ERROR "not enough arguments to return\n\thave \(string\)\n\twant \(string, int\)|not enough arguments to return"
+               return "" // ERROR "not enough arguments to return\n\thave \(string\)\n\twant \(string, int\)|not enough arguments to return|wrong number of return values"
        default:
                return "lizard", 10
        }
@@ -40,14 +40,14 @@ type U float64
 
 func foo5() (S, T, U) {
        if false {
-               return "" // ERROR "not enough arguments to return\n\thave \(string\)\n\twant \(S, T, U\)|not enough arguments to return"
+               return "" // ERROR "not enough arguments to return\n\thave \(string\)\n\twant \(S, T, U\)|not enough arguments to return|wrong number of return values"
        } else {
                ptr := new(T)
-               return ptr // ERROR "not enough arguments to return\n\thave \(\*T\)\n\twant \(S, T, U\)|not enough arguments to return"
+               return ptr // ERROR "not enough arguments to return\n\thave \(\*T\)\n\twant \(S, T, U\)|not enough arguments to return|wrong number of return values"
        }
-       return new(S), 12.34, 1 + 0i, 'r', true // ERROR "too many arguments to return\n\thave \(\*S, number, number, number, bool\)\n\twant \(S, T, U\)|too many values in return statement"
+       return new(S), 12.34, 1 + 0i, 'r', true // ERROR "too many arguments to return\n\thave \(\*S, number, number, number, bool\)\n\twant \(S, T, U\)|too many values in return statement|wrong number of return values"
 }
 
 func foo6() (T, string) {
-       return "T", true, true // ERROR "too many arguments to return\n\thave \(string, bool, bool\)\n\twant \(T, string\)|too many values in return statement"
+       return "T", true, true // ERROR "too many arguments to return\n\thave \(string, bool, bool\)\n\twant \(T, string\)|too many values in return statement|wrong number of return values"
 }
index d11ce51b97109e7bb0ba67e3f5bc92d582ddf1e0..81e3edf5e3fb6e5746279964d5c2c6b6ad292206 100644 (file)
@@ -9,13 +9,13 @@
 package p
 
 func F1(s []byte) []byte {
-       return s[2:1]           // ERROR "invalid slice index|inverted slice range"
+       return s[2:1]           // ERROR "invalid slice index|inverted slice range|invalid slice indices"
 }
 
 func F2(a [10]byte) []byte {
-       return a[2:1]           // ERROR "invalid slice index|inverted slice range"
+       return a[2:1]           // ERROR "invalid slice index|inverted slice range|invalid slice indices"
 }
 
 func F3(s string) string {
-       return s[2:1]           // ERROR "invalid slice index|inverted slice range"
+       return s[2:1]           // ERROR "invalid slice index|inverted slice range|invalid slice indices"
 }
index 9eb2e0f9c2ad31b2b273fdf24bbb5a864aaea5d6..3af6f9761b3746d05083524eca69ccf5839102db 100644 (file)
@@ -12,5 +12,5 @@ type a struct {
 
 func main() {
   av := a{};
-  _ = *a(av); // ERROR "invalid indirect|expected pointer"
+  _ = *a(av); // ERROR "invalid indirect|expected pointer|cannot indirect"
 }
index 59cfa9fcee811063a2f6706ae7281f748b6749b8..6ac6d86db3b0cca0d110a5eb75b37c1a8676aeae 100644 (file)
@@ -16,5 +16,5 @@ func (T) foo() {}
 func main() {
        av := T{}
        pav := &av
-       (**T).foo(&pav) // ERROR "no method .*foo|requires named type or pointer to named"
+       (**T).foo(&pav) // ERROR "no method .*foo|requires named type or pointer to named|undefined"
 }
index d92247845585a7e6bb65d5fb970d4d861ed5058f..1dc556380ea96b8eb7760f680477f510d7cc9cf3 100644 (file)
@@ -13,4 +13,5 @@ func main() {
        switch (i.(type)) { // ERROR "outside type switch"
        default:
        }
+       _ = i
 }
index 197c225c6f06b3d8799474c86e1f2f8ecdb94564..d732e1fa1df5dc39784847dd98f90334a74420e6 100644 (file)
@@ -6,4 +6,4 @@
 
 package p
 
-import init "fmt" // ERROR "cannot import package as init"
+import init "fmt" // ERROR "cannot import package as init|cannot declare init"
index 09e1b850990c84f729cab9c2d472af7136883f23..27ae29438fbada6b5b674d0192a520981dbe19f8 100644 (file)
@@ -27,8 +27,8 @@ type B struct {
 var t T
 var p *T
 
-const N1 = unsafe.Offsetof(t.X)      // ERROR "indirection"
-const N2 = unsafe.Offsetof(p.X)      // ERROR "indirection"
+const N1 = unsafe.Offsetof(t.X)      // ERROR "indirection|field X is embedded via a pointer in T"
+const N2 = unsafe.Offsetof(p.X)      // ERROR "indirection|field X is embedded via a pointer in T"
 const N3 = unsafe.Offsetof(t.B.X)    // valid
 const N4 = unsafe.Offsetof(p.B.X)    // valid
 const N5 = unsafe.Offsetof(t.Method) // ERROR "method value"
index ecde9ae5105c88ea7564584ca253525e6926e198..db83e94b86fee432d7373fd1735609d0e73133fc 100644 (file)
@@ -9,5 +9,5 @@
 package p
 
 func f() uintptr {
-       return nil // ERROR "cannot use nil as type uintptr in return argument|incompatible type"
+       return nil // ERROR "cannot use nil as type uintptr in return argument|incompatible type|cannot convert nil"
 }
index e4465e9d1eb7ef6a5fb7a34b736db6797fd9d82b..9f4d2de0e3fd116c6f7ae5a52bf36169bb59f87e 100644 (file)
@@ -17,5 +17,6 @@ func bar() (T, string, T) { // ERROR "undefined"
 func main() {
        var x, y, z int
        x, y = foo()
-       x, y, z = bar() // ERROR "cannot (use type|assign) string"
+       x, y, z = bar() // ERROR "cannot (use type|assign) string|incompatible type"
+       _, _, _ = x, y, z
 }
index f62a85009c0fbb396bc6d818cb06094ced453543..fca4e66aafe7615c0d52e4a42f861c4289e80ed1 100644 (file)
@@ -18,5 +18,5 @@ func printmany(nums ...int) {
 func main() {
        printmany(1, 2, 3)
        printmany([]int{1, 2, 3}...)
-       printmany(1, "abc", []int{2, 3}...) // ERROR "too many arguments in call to printmany\n\thave \(number, string, \.\.\.int\)\n\twant \(...int\)"
+       printmany(1, "abc", []int{2, 3}...) // ERROR "too many arguments in call( to printmany\n\thave \(number, string, \.\.\.int\)\n\twant \(...int\))?"
 }
index 5bd15ba72ece24fead41e144f48293c86ea3acee..5cc89b47b537e7db05059d6b70d038d3c1972d58 100644 (file)
@@ -7,14 +7,14 @@
 package p
 
 func f1() {
-       for a, a := range []int{1, 2, 3} { // ERROR "a.* repeated on left side of :="
+       for a, a := range []int{1, 2, 3} { // ERROR "a.* repeated on left side of :=|a redeclared"
                println(a)
        }
 }
 
 func f2() {
        var a int
-       for a, a := range []int{1, 2, 3} { // ERROR "a.* repeated on left side of :="
+       for a, a := range []int{1, 2, 3} { // ERROR "a.* repeated on left side of :=|a redeclared"
                println(a)
        }
        println(a)
index 2765200ac89fcff5045068fa2cb4f0418c21eaa6..70dc26303e188d9dbbb976adb8b481bd897f5a0f 100644 (file)
@@ -15,7 +15,7 @@ func g() bool { return true }
 func h(int, int) {}
 
 func main() {
-       f(g())        // ERROR "in argument to f|incompatible type"
-       f(true)       // ERROR "in argument to f|incompatible type"
-       h(true, true) // ERROR "in argument to h|incompatible type"
+       f(g())        // ERROR "in argument to f|incompatible type|cannot convert"
+       f(true)       // ERROR "in argument to f|incompatible type|cannot convert"
+       h(true, true) // ERROR "in argument to h|incompatible type|cannot convert"
 }
index 7cddf4875eb3ddaeea2104608c29f3a18b30cafd..52eed93756f7c36c37004e7931842bb61bde213e 100644 (file)
@@ -9,7 +9,7 @@
 package main
 
 func main() {
-       _ = [0]int{-1: 50}              // ERROR "index must be non-negative integer constant|index expression is negative"
+       _ = [0]int{-1: 50}              // ERROR "index must be non-negative integer constant|index expression is negative|must not be negative"
        _ = [0]int{0: 0}                // ERROR "index 0 out of bounds \[0:0\]|out of range"
        _ = [0]int{5: 25}               // ERROR "index 5 out of bounds \[0:0\]|out of range"
        _ = [10]int{2: 10, 15: 30}      // ERROR "index 15 out of bounds \[0:10\]|out of range"
index e8b95d5db827a9a0155481be8a8401036606cd64..12cd62b65334ba3b79d15d7f3e5516a39ee4b6a5 100644 (file)
@@ -8,4 +8,4 @@
 
 package p
 
-var _ = []int{a: true, true} // ERROR "undefined: a" "cannot use true \(type untyped bool\) as type int in slice literal|undefined name .*a|incompatible type"
+var _ = []int{a: true, true} // ERROR "undefined: a" "cannot use true \(type untyped bool\) as type int in slice literal|undefined name .*a|incompatible type|cannot convert"
index 0ec3476403dbe45bac7856ffc1d11aa7c0499041..c78de287ff61f3988c54a9a1c8eeb0a103d7f0fc 100644 (file)
@@ -12,9 +12,9 @@ const bits2 uint = 10
 func main() {
        _ = make([]byte, 1<<bits1)
        _ = make([]byte, 1<<bits2)
-       _ = make([]byte, nil) // ERROR "non-integer.*len"
-       _ = make([]byte, nil, 2) // ERROR "non-integer.*len"
-       _ = make([]byte, 1, nil) // ERROR "non-integer.*cap"
-       _ = make([]byte, true) // ERROR "non-integer.*len"
-       _ = make([]byte, "abc") // ERROR "non-integer.*len"
+       _ = make([]byte, nil) // ERROR "non-integer.*len|untyped nil"
+       _ = make([]byte, nil, 2) // ERROR "non-integer.*len|untyped nil"
+       _ = make([]byte, 1, nil) // ERROR "non-integer.*cap|untyped nil"
+       _ = make([]byte, true) // ERROR "non-integer.*len|untyped bool"
+       _ = make([]byte, "abc") // ERROR "non-integer.*len|untyped string"
 }
index ba50e4237b38cd479cd016dc39d42929576cb0e7..4d10e47e64a518651b6ae19e52aa57c792f9a6ec 100644 (file)
@@ -9,7 +9,7 @@
 package main
 
 func main() {
-       _ = copy(nil, []int{}) // ERROR "use of untyped nil|left argument must be a slice"
-       _ = copy([]int{}, nil) // ERROR "use of untyped nil|second argument must be slice or string"
-       _ = 1 + true           // ERROR "mismatched types untyped int and untyped bool|incompatible types"
+       _ = copy(nil, []int{}) // ERROR "use of untyped nil|left argument must be a slice|expects slice arguments"
+       _ = copy([]int{}, nil) // ERROR "use of untyped nil|second argument must be slice or string|expects slice arguments"
+       _ = 1 + true           // ERROR "mismatched types untyped int and untyped bool|incompatible types|cannot convert"
 }
index caac66734617841f71c371598efbbb6fbc8be205..fe2dff786c4288213c9bcb4f4bfdb1d8b0405892 100644 (file)
@@ -12,12 +12,12 @@ const (
        ok = byte(iota + 253)
        bad
        barn
-       bard // ERROR "constant 256 overflows byte|integer constant overflow"
+       bard // ERROR "constant 256 overflows byte|integer constant overflow|cannot convert"
 )
 
 const (
        c = len([1 - iota]int{})
        d
-       e // ERROR "array bound must be non-negative|negative array bound"
-       f // ERROR "array bound must be non-negative|negative array bound"
+       e // ERROR "array bound must be non-negative|negative array bound|invalid array length"
+       f // ERROR "array bound must be non-negative|negative array bound|invalid array length"
 )
index f433e36924a38009690a9f1e77dd3fb96d2571e1..fcbb4f86ec1a71fdfe09476311a431b41e361c1b 100644 (file)
@@ -10,8 +10,8 @@
 package main
 
 func main() {
-       _ = []byte{"foo"}   // ERROR "cannot use|incompatible type"
-       _ = []int{"foo"}    // ERROR "cannot use|incompatible type"
-       _ = []rune{"foo"}   // ERROR "cannot use|incompatible type"
+       _ = []byte{"foo"}   // ERROR "cannot use|incompatible type|cannot convert"
+       _ = []int{"foo"}    // ERROR "cannot use|incompatible type|cannot convert"
+       _ = []rune{"foo"}   // ERROR "cannot use|incompatible type|cannot convert"
        _ = []string{"foo"} // OK
 }
index e9c5b54d51d2e1c8b4fd1563f025a75b5cc60678..1d9fa936c4c096c51cb9b03f2191f34bcb227760 100644 (file)
@@ -7,5 +7,5 @@
 package main
 
 func main() {
-       n.foo = 6 // ERROR "undefined: n in n.foo|undefined name .*n"
+       n.foo = 6 // ERROR "undefined: n in n.foo|undefined name .*n|undefined: n"
 }
index fee2ca7ce0574a5716f4bdcb75b848b12944c0dd..c2d00a7ebd4be0a802cd4aa466a1bb6a149bc681 100644 (file)
@@ -9,5 +9,5 @@
 package p
 
 func f(s string) {
-       var _ float64 = s[2] // ERROR "cannot use.*type byte.*as type float64"
+       var _ float64 = s[2] // ERROR "cannot use.*type byte.*as type float64|cannot use .* as float64 value"
 }
index d4762f802e0914ef04fa38e7e1497bf15096bd65..f5c5296a2bf7c60dd05f8cdc6ebeb302e2c72195 100644 (file)
@@ -13,6 +13,7 @@ const zero = 0
 
 func main() {
        var x int
+       _ = x
        x = make(map[int]int) // ERROR "cannot use make\(map\[int\]int\)|incompatible"
        x = make(map[int]int, 0) // ERROR "cannot use make\(map\[int\]int, 0\)|incompatible"
        x = make(map[int]int, zero) // ERROR "cannot use make\(map\[int\]int, zero\)|incompatible"
index 6cc8d5b9e5d37418aeeee47de44a2acc7fd67fd9..1a4510316dffaca59838d9546914e1f2274e5a24 100644 (file)
@@ -33,24 +33,24 @@ var (
 var (
        _ = e == c
        _ = e != c
-       _ = e >= c // ERROR "invalid operation.*not defined|invalid comparison"
+       _ = e >= c // ERROR "invalid operation.*not defined|invalid comparison|cannot compare"
        _ = c == e
        _ = c != e
-       _ = c >= e // ERROR "invalid operation.*not defined|invalid comparison"
+       _ = c >= e // ERROR "invalid operation.*not defined|invalid comparison|cannot compare"
 
        _ = i == c
        _ = i != c
-       _ = i >= c // ERROR "invalid operation.*not defined|invalid comparison"
+       _ = i >= c // ERROR "invalid operation.*not defined|invalid comparison|cannot compare"
        _ = c == i
        _ = c != i
-       _ = c >= i // ERROR "invalid operation.*not defined|invalid comparison"
+       _ = c >= i // ERROR "invalid operation.*not defined|invalid comparison|cannot compare"
 
        _ = e == n
        _ = e != n
-       _ = e >= n // ERROR "invalid operation.*not defined|invalid comparison"
+       _ = e >= n // ERROR "invalid operation.*not defined|invalid comparison|cannot compare"
        _ = n == e
        _ = n != e
-       _ = n >= e // ERROR "invalid operation.*not defined|invalid comparison"
+       _ = n >= e // ERROR "invalid operation.*not defined|invalid comparison|cannot compare"
 
        // i and n are not assignable to each other
        _ = i == n // ERROR "invalid operation.*mismatched types|incompatible types"
@@ -67,12 +67,12 @@ var (
        _ = 1 != e
        _ = 1 >= e // ERROR "invalid operation.*not defined|invalid comparison"
 
-       _ = i == 1 // ERROR "invalid operation.*mismatched types|incompatible types"
-       _ = i != 1 // ERROR "invalid operation.*mismatched types|incompatible types"
-       _ = i >= 1 // ERROR "invalid operation.*mismatched types|incompatible types"
-       _ = 1 == i // ERROR "invalid operation.*mismatched types|incompatible types"
-       _ = 1 != i // ERROR "invalid operation.*mismatched types|incompatible types"
-       _ = 1 >= i // ERROR "invalid operation.*mismatched types|incompatible types"
+       _ = i == 1 // ERROR "invalid operation.*mismatched types|incompatible types|cannot convert"
+       _ = i != 1 // ERROR "invalid operation.*mismatched types|incompatible types|cannot convert"
+       _ = i >= 1 // ERROR "invalid operation.*mismatched types|incompatible types|cannot convert"
+       _ = 1 == i // ERROR "invalid operation.*mismatched types|incompatible types|cannot convert"
+       _ = 1 != i // ERROR "invalid operation.*mismatched types|incompatible types|cannot convert"
+       _ = 1 >= i // ERROR "invalid operation.*mismatched types|incompatible types|cannot convert"
 
        _ = e == f // ERROR "invalid operation.*not defined|invalid operation"
        _ = e != f // ERROR "invalid operation.*not defined|invalid operation"
index e8946a5be25cbd190674cc89e85b44af26bc89a6..3df3b9097b57ed67fa7196aa664411b3f4f8f4d1 100644 (file)
@@ -9,7 +9,7 @@
 // See golang.org/issue/9432.
 package p
 
-type foo struct { // ERROR "invalid recursive type"
+type foo struct { // ERROR "invalid recursive type|cycle"
        bar  foo
        blah foo
 }
index 2d5aae4a30e6c4c32b3c65562e79afd86bac342f..86e3e9a2dfd42d215610cf3155da2afd8f1677a6 100644 (file)
@@ -14,5 +14,5 @@ func main() {
                t []int
                u int
        }{}
-       _ = append(s, 0) // ERROR "must be a slice|must be slice"
+       _ = append(s, 0) // ERROR "must be a slice|must be slice|not a slice"
 }
index fb6f56184fac2b683efd4c9f7d77856cf582a68b..ec25161d13c675c61bb6b21ffc8310a262a80c5f 100644 (file)
@@ -14,6 +14,6 @@ func f1(a int) (int, float32) {
 }
 
 
-func f2(a int) (a int, b float32) { // ERROR "duplicate argument a|definition"
+func f2(a int) (a int, b float32) { // ERROR "duplicate argument a|definition|redeclared"
        return 8, 8.0
 }
index 7b05d1260664f168126929f8092c4031b09566bb..3dbb15b0d4949167e65b0bdda0daea83825c62d7 100644 (file)
@@ -7,21 +7,21 @@
 package p
 
 type T interface {
-       F1(i int) (i int) // ERROR "duplicate argument i|redefinition|previous"
-       F2(i, i int) // ERROR "duplicate argument i|redefinition|previous"
-       F3() (i, i int) // ERROR "duplicate argument i|redefinition|previous"
+       F1(i int) (i int) // ERROR "duplicate argument i|redefinition|previous|redeclared"
+       F2(i, i int) // ERROR "duplicate argument i|redefinition|previous|redeclared"
+       F3() (i, i int) // ERROR "duplicate argument i|redefinition|previous|redeclared"
 }
 
-type T1 func(i, i int) // ERROR "duplicate argument i|redefinition|previous"
-type T2 func(i int) (i int) // ERROR "duplicate argument i|redefinition|previous"
-type T3 func() (i, i int) // ERROR "duplicate argument i|redefinition|previous"
+type T1 func(i, i int) // ERROR "duplicate argument i|redefinition|previous|redeclared"
+type T2 func(i int) (i int) // ERROR "duplicate argument i|redefinition|previous|redeclared"
+type T3 func() (i, i int) // ERROR "duplicate argument i|redefinition|previous|redeclared"
 
 type R struct{}
 
-func (i *R) F1(i int)         {} // ERROR "duplicate argument i|redefinition|previous"
-func (i *R) F2() (i int)      {return 0} // ERROR "duplicate argument i|redefinition|previous"
-func (i *R) F3(j int) (j int) {return 0} // ERROR "duplicate argument j|redefinition|previous"
+func (i *R) F1(i int)         {} // ERROR "duplicate argument i|redefinition|previous|redeclared"
+func (i *R) F2() (i int)      {return 0} // ERROR "duplicate argument i|redefinition|previous|redeclared"
+func (i *R) F3(j int) (j int) {return 0} // ERROR "duplicate argument j|redefinition|previous|redeclared"
 
-func F1(i, i int)      {} // ERROR "duplicate argument i|redefinition|previous"
-func F2(i int) (i int) {return 0} // ERROR "duplicate argument i|redefinition|previous"
-func F3() (i, i int)   {return 0, 0} // ERROR "duplicate argument i|redefinition|previous"
+func F1(i, i int)      {} // ERROR "duplicate argument i|redefinition|previous|redeclared"
+func F2(i int) (i int) {return 0} // ERROR "duplicate argument i|redefinition|previous|redeclared"
+func F3() (i, i int)   {return 0, 0} // ERROR "duplicate argument i|redefinition|previous|redeclared"
index 9513ef46bdd6f252e30878de05dd0b6274d42875..2ee3024e5ccd91fc0b4abc3242c102eecc63fd58 100644 (file)
@@ -7,11 +7,11 @@
 package p
 
 var T interface {
-       F1(i int) (i int) // ERROR "duplicate argument i|redefinition|previous"
-       F2(i, i int) // ERROR "duplicate argument i|redefinition|previous"
-       F3() (i, i int) // ERROR "duplicate argument i|redefinition|previous"
+       F1(i int) (i int) // ERROR "duplicate argument i|redefinition|previous|redeclared"
+       F2(i, i int) // ERROR "duplicate argument i|redefinition|previous|redeclared"
+       F3() (i, i int) // ERROR "duplicate argument i|redefinition|previous|redeclared"
 }
 
-var T1 func(i, i int) // ERROR "duplicate argument i|redefinition|previous"
-var T2 func(i int) (i int) // ERROR "duplicate argument i|redefinition|previous"
-var T3 func() (i, i int) // ERROR "duplicate argument i|redefinition|previous"
+var T1 func(i, i int) // ERROR "duplicate argument i|redefinition|previous|redeclared"
+var T2 func(i int) (i int) // ERROR "duplicate argument i|redefinition|previous|redeclared"
+var T3 func() (i, i int) // ERROR "duplicate argument i|redefinition|previous|redeclared"
index 5e182281da8ca32018ef1c45e4780ca8e798c425..43bb3c6503e99294480a0bbbce847e47e0372bc6 100644 (file)
@@ -14,6 +14,6 @@ func init() {
 
 func main() {
        init()         // ERROR "undefined.*init"
-       runtime.init() // ERROR "undefined.*runtime\.init|reference to undefined name"
+       runtime.init() // ERROR "undefined.*runtime\.init|reference to undefined name|undefined: runtime"
        var _ = init   // ERROR "undefined.*init"
 }
index d90395d7535bf88f80358422798bc883318c01cc..b1a8470b3a0b15b3824375f24b34509def075fbe 100644 (file)
@@ -11,7 +11,7 @@ package main
 
 var (
        x int = a
-       a int = b // ERROR "a refers to\n.*b refers to\n.*c refers to\n.*a"
+       a int = b // ERROR "a refers to\n.*b refers to\n.*c refers to\n.*a|initialization loop"
        b int = c
        c int = a
 )
index df3e2e435bb26051215cad9a85550f65d820f05a..97a2d963f04ac717aabea63de11108311eac2f4c 100644 (file)
@@ -48,25 +48,25 @@ func main() {
        check("t.M()", t.M())
        check("pt.M()", pt.M())
        check("ti.M()", ti.M())
-       check("pti.M()", pti.M()) // ERROR "pointer to interface, not interface"
+       check("pti.M()", pti.M()) // ERROR "pointer to interface, not interface|no field or method M"
        check("s.M()", s.M())
        check("ps.M()", ps.M())
 
        i = t
        check("i = t; i.M()", i.M())
-       check("i = t; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
+       check("i = t; pi.M()", pi.M()) // ERROR "pointer to interface, not interface|no field or method M"
 
        i = pt
        check("i = pt; i.M()", i.M())
-       check("i = pt; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
+       check("i = pt; pi.M()", pi.M()) // ERROR "pointer to interface, not interface|no field or method M"
 
        i = s
        check("i = s; i.M()", i.M())
-       check("i = s; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
+       check("i = s; pi.M()", pi.M()) // ERROR "pointer to interface, not interface|no field or method M"
 
        i = ps
        check("i = ps; i.M()", i.M())
-       check("i = ps; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
+       check("i = ps; pi.M()", pi.M()) // ERROR "pointer to interface, not interface|no field or method M"
 
        if !ok {
                println("BUG: interface10")
index b705b976760071f6cf132c0a4be545ddc1945882..1b7af6712b661df40e890e2292fa5a0519248212 100644 (file)
@@ -38,7 +38,7 @@ var e E
 
 func main() {
        e = t // ok
-       t = e // ERROR "need explicit|need type assertion"
+       t = e // ERROR "need explicit|need type assertion|incompatible type"
 
        // neither of these can work,
        // because i has an extra method
@@ -50,14 +50,14 @@ func main() {
        i2 = i // ERROR "incompatible|missing N method"
 
        i = I(i2)  // ok
-       i2 = I2(i) // ERROR "invalid|missing N method"
+       i2 = I2(i) // ERROR "invalid|missing N method|cannot convert"
 
        e = E(t) // ok
-       t = T(e) // ERROR "need explicit|need type assertion|incompatible"
+       t = T(e) // ERROR "need explicit|need type assertion|incompatible|cannot convert"
 
        // cannot type-assert non-interfaces
        f := 2.0
-       _ = f.(int) // ERROR "non-interface type|only valid for interface types"
+       _ = f.(int) // ERROR "non-interface type|only valid for interface types|not an interface type"
 
 }
 
@@ -83,8 +83,8 @@ var jj Int
 var m1 M = ii // ERROR "incompatible|missing"
 var m2 M = jj // ERROR "incompatible|wrong type for M method"
 
-var m3 = M(ii) // ERROR "invalid|missing"
-var m4 = M(jj) // ERROR "invalid|wrong type for M method"
+var m3 = M(ii) // ERROR "invalid|missing|cannot convert"
+var m4 = M(jj) // ERROR "invalid|wrong type for M method|cannot convert"
 
 type B1 interface {
        _() // ERROR "methods must have a unique non-blank name"
index 2927050669a9f58e710a577258d6ad28bc1a7bce..c21e4da390ab0fd92df3288c2d2d64fe994eb649 100644 (file)
@@ -32,7 +32,9 @@ func AddInst(Inst) *Inst {
 
 func main() {
        print("call addinst\n")
-       var x Inst = AddInst(new(Start)) // ERROR "pointer to interface"
+       var x Inst = AddInst(new(Start)) // ERROR "pointer to interface|incompatible type"
+       _ = x
        print("return from  addinst\n")
        var y *Inst = new(Start)  // ERROR "pointer to interface|incompatible type"
+       _ = y
 }
index 2b7ccdc1a7bdcad99d8a00834b154fee59187293..a0a87534a4a472e8643a9c6d0c8724f0e38fea09 100644 (file)
@@ -37,14 +37,14 @@ func main() {
        var sp SP
 
        v = t
-       p = t // ERROR "does not implement|requires a pointer"
+       p = t // ERROR "does not implement|requires a pointer|cannot use"
        _, _ = v, p
        v = &t
        p = &t
        _, _ = v, p
 
        v = s
-       p = s // ERROR "does not implement|requires a pointer"
+       p = s // ERROR "does not implement|requires a pointer|cannot use"
        _, _ = v, p
        v = &s
        p = &s
index 6608620db396681d6b5e5c351b0fc68caa36123b..30a57456b31764ceea3babe723ae57b0b816d305 100644 (file)
@@ -15,14 +15,14 @@ type T chan byte
 var sink T
 
 func main() {
-       sink = make(T, -1)            // ERROR "negative buffer argument in make.*"
-       sink = make(T, uint64(1<<63)) // ERROR "buffer argument too large in make.*"
+       sink = make(T, -1)            // ERROR "negative buffer argument in make.*|must not be negative"
+       sink = make(T, uint64(1<<63)) // ERROR "buffer argument too large in make.*|out of bounds"
 
-       sink = make(T, 0.5) // ERROR "constant 0.5 truncated to integer"
+       sink = make(T, 0.5) // ERROR "constant 0.5 truncated to integer|truncated to int"
        sink = make(T, 1.0)
-       sink = make(T, float32(1.0)) // ERROR "non-integer buffer argument in make.*"
-       sink = make(T, float64(1.0)) // ERROR "non-integer buffer argument in make.*"
+       sink = make(T, float32(1.0)) // ERROR "non-integer buffer argument in make.*|must be integer"
+       sink = make(T, float64(1.0)) // ERROR "non-integer buffer argument in make.*|must be integer"
        sink = make(T, 1+0i)
-       sink = make(T, complex64(1+0i))  // ERROR "non-integer buffer argument in make.*"
-       sink = make(T, complex128(1+0i)) // ERROR "non-integer buffer argument in make.*"
+       sink = make(T, complex64(1+0i))  // ERROR "non-integer buffer argument in make.*|must be integer"
+       sink = make(T, complex128(1+0i)) // ERROR "non-integer buffer argument in make.*|must be integer"
 }
index 63998d708c31228ce5adc2d028de23d0800025e6..a60f5b5ee50059397ad27fd9f2b08dd2a5875809 100644 (file)
@@ -15,20 +15,20 @@ type T map[int]int
 var sink T
 
 func main() {
-       sink = make(T, -1)            // ERROR "negative size argument in make.*"
-       sink = make(T, uint64(1<<63)) // ERROR "size argument too large in make.*"
+       sink = make(T, -1)            // ERROR "negative size argument in make.*|must not be negative"
+       sink = make(T, uint64(1<<63)) // ERROR "size argument too large in make.*|out of bounds"
 
        // Test that errors are emitted at call sites, not const declarations
        const x = -1
-       sink = make(T, x) // ERROR "negative size argument in make.*"
+       sink = make(T, x) // ERROR "negative size argument in make.*|must not be negative"
        const y = uint64(1 << 63)
-       sink = make(T, y) // ERROR "size argument too large in make.*"
+       sink = make(T, y) // ERROR "size argument too large in make.*|out of bounds"
 
-       sink = make(T, 0.5) // ERROR "constant 0.5 truncated to integer"
+       sink = make(T, 0.5) // ERROR "constant 0.5 truncated to integer|truncated to int"
        sink = make(T, 1.0)
-       sink = make(T, float32(1.0)) // ERROR "non-integer size argument in make.*"
-       sink = make(T, float64(1.0)) // ERROR "non-integer size argument in make.*"
+       sink = make(T, float32(1.0)) // ERROR "non-integer size argument in make.*|must be integer"
+       sink = make(T, float64(1.0)) // ERROR "non-integer size argument in make.*|must be integer"
        sink = make(T, 1+0i)
-       sink = make(T, complex64(1+0i))  // ERROR "non-integer size argument in make.*"
-       sink = make(T, complex128(1+0i)) // ERROR "non-integer size argument in make.*"
+       sink = make(T, complex64(1+0i))  // ERROR "non-integer size argument in make.*|must be integer"
+       sink = make(T, complex128(1+0i)) // ERROR "non-integer size argument in make.*|must be integer"
 }
index 058d975898251c590d2b38d6d9dba1769b9f1ad3..14854dcf0c8fe70e4ae766cbdf74b9ee3a612d4f 100644 (file)
 package main
 
 func main() {
-       _ = make()      // ERROR "missing argument"
-       _ = make(int)   // ERROR "cannot make type"
-       _ = make([]int) // ERROR "missing len argument"
+       _ = make()      // ERROR "missing argument|not enough arguments"
+       _ = make(int)   // ERROR "cannot make type|cannot make int"
+       _ = make([]int) // ERROR "missing len argument|expects 2 or 3 arguments"
 
-       _ = new()       // ERROR "missing argument"
+       _ = new()       // ERROR "missing argument|not enough arguments"
        _ = new(int, 2) // ERROR "too many arguments"
 }
index b4aa70755feb0ed88f43a9b8a3c50dd6ad1d3e83..a6b27e6ebd3a6b14502a69d889bb9fc84216bb75 100644 (file)
@@ -64,5 +64,5 @@ func main() {
        delete()        // ERROR "missing arguments|not enough arguments"
        delete(m)       // ERROR "missing second \(key\) argument|not enough arguments"
        delete(m, 2, 3) // ERROR "too many arguments"
-       delete(1, m)    // ERROR "first argument to delete must be map|argument 1 must be a map"
+       delete(1, m)    // ERROR "first argument to delete must be map|argument 1 must be a map|is not a map"
 }
index ac1d771c0504f19c6888cd44f2cbd4b9e3ec36ec..2a92136d6c10baae3a901e61207f0f2a3e279406 100644 (file)
@@ -15,8 +15,8 @@ type T struct {
 type P *T
 type P1 *T
 
-func (p P) val() int   { return 1 } // ERROR "receiver.* pointer|invalid pointer or interface receiver"
-func (p *P1) val() int { return 1 } // ERROR "receiver.* pointer|invalid pointer or interface receiver"
+func (p P) val() int   { return 1 } // ERROR "receiver.* pointer|invalid pointer or interface receiver|invalid receiver"
+func (p *P1) val() int { return 1 } // ERROR "receiver.* pointer|invalid pointer or interface receiver|invalid receiver"
 
 type I interface{}
 type I1 interface{}
@@ -38,4 +38,4 @@ var _ = pv.val   // ERROR "undefined|pointer to interface"
 
 func (t *T) g() int { return t.a }
 
-var _ = (T).g() // ERROR "needs pointer receiver|undefined|method requires pointer"
+var _ = (T).g() // ERROR "needs pointer receiver|undefined|method requires pointer|cannot call pointer method"
index 20eccce413a10c838864ef9822b68e29c365d56f..ede3467c5c26c3aa558dbe3e2a763b66f775f457 100644 (file)
@@ -18,5 +18,5 @@ func (*B) g() {}
 
 var _ = func() {
        var a A
-       A(a).g() // ERROR "cannot call pointer method on|cannot take the address of"
+       A(a).g() // ERROR "cannot call pointer method .*on|cannot take the address of"
 }
index 7feae13b9d7045f9cd405ad13dbc559df56a7695..452c6da27e259c543fc9833578a0a1bc63bff7b8 100644 (file)
@@ -54,7 +54,7 @@ func main() {
        _ = b
 
        _, bb := <-c
-       asBool(bb) // ERROR "cannot use.*type bool.*as type Bool"
+       asBool(bb) // ERROR "cannot use.*type bool.*as type Bool|cannot use bb"
        _, b = <-c // ok now
        _ = b
 
index c49a70a263d11f064c33323c77a5e7838bf0ce80..058db4494a06b56a75bc516ad1519f70c8966bd7 100644 (file)
@@ -13,7 +13,7 @@ func main() {
        var n byte         // ERROR "not a type|expected type"
        var y = float32(0) // ERROR "cannot call|expected function"
        const (
-               a = 1 + iota // ERROR "invalid operation|incompatible types"
+               a = 1 + iota // ERROR "invalid operation|incompatible types|cannot convert"
        )
 
 }
index db3e9f6c2fc18040fc63b81c27375b90c53031d1..fcf8a4fcc96f697682f1df5b388166db4bc154c7 100644 (file)
@@ -59,7 +59,7 @@ var (
 
        // dirs are the directories to look for *.go files in.
        // TODO(bradfitz): just use all directories?
-       dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime"}
+       dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime", "typeparam"}
 
        // ratec controls the max number of tests running at a time.
        ratec chan bool
@@ -741,7 +741,83 @@ func (t *test) run() {
                        t.updateErrors(string(out), long)
                }
                t.err = t.errorCheck(string(out), wantAuto, long, t.gofile)
-               return
+               if t.err != nil {
+                       return // don't hide error if run below succeeds
+               }
+
+               // The following is temporary scaffolding to get types2 typechecker
+               // up and running against the existing test cases. The explicitly
+               // listed files don't pass yet, usually because the error messages
+               // are slightly different (this list is not complete). Any errorcheck
+               // tests that require output from analysis phases past intial type-
+               // checking are also excluded since these phases are not running yet.
+               // We can get rid of this code once types2 is fully plugged in.
+
+               // For now we're done when we can't handle the file or some of the flags.
+               // The first goal is to eliminate the excluded list; the second goal is to
+               // eliminate the flag list.
+
+               // Excluded files.
+               if excluded[t.goFileName()] {
+                       if *verbose {
+                               fmt.Printf("excl\t%s\n", t.goFileName())
+                       }
+                       return // cannot handle file yet
+               }
+
+               // Excluded flags.
+               for _, flag := range flags {
+                       for _, pattern := range []string{
+                               "-+",
+                               "-0",
+                               "-e=0",
+                               "-m",
+                               "-live",
+                               "-std",
+                               "wb",
+                               "append",
+                               "slice",
+                               "typeassert",
+                               "ssa/check_bce/debug",
+                               "ssa/intrinsics/debug",
+                               "ssa/opt/debug",
+                               "ssa/prove/debug",
+                               "ssa/likelyadjust/debug",
+                               "ssa/insert_resched_checks/off",
+                               "ssa/phiopt/debug",
+                               "defer",
+                               "nil",
+                       } {
+                               if strings.Contains(flag, pattern) {
+                                       if *verbose {
+                                               fmt.Printf("excl\t%s\t%s\n", t.goFileName(), flags)
+                                       }
+                                       return // cannot handle flag
+                               }
+                       }
+               }
+
+               // Run errorcheck again with -G option (new typechecker).
+               cmdline = []string{goTool(), "tool", "compile", "-G", "-C", "-e", "-o", "a.o"}
+               // No need to add -dynlink even if linkshared if we're just checking for errors...
+               cmdline = append(cmdline, flags...)
+               cmdline = append(cmdline, long)
+               out, err = runcmd(cmdline...)
+               if wantError {
+                       if err == nil {
+                               t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out)
+                               return
+                       }
+               } else {
+                       if err != nil {
+                               t.err = err
+                               return
+                       }
+               }
+               if *updateErrors {
+                       t.updateErrors(string(out), long)
+               }
+               t.err = t.errorCheck(string(out), wantAuto, long, t.gofile)
 
        case "compile":
                // Compile Go file.
@@ -1846,3 +1922,78 @@ func overlayDir(dstRoot, srcRoot string) error {
                return err
        })
 }
+
+// List of files that the compiler cannot errorcheck with the new typechecker (compiler -G option).
+// Temporary scaffolding until we pass all the tests at which point this map can be removed.
+var excluded = map[string]bool{
+       "complit1.go":     true, // types2 reports extra errors
+       "const2.go":       true, // types2 not run after syntax errors
+       "ddd1.go":         true, // issue #42987
+       "directive.go":    true, // misplaced compiler directive checks
+       "float_lit3.go":   true, // types2 reports extra errors
+       "import1.go":      true, // types2 reports extra errors
+       "import5.go":      true, // issue #42988
+       "import6.go":      true, // issue #43109
+       "initializerr.go": true, // types2 reports extra errors
+       "linkname2.go":    true, // error reported by noder (not running for types2 errorcheck test)
+       "shift1.go":       true, // issue #42989
+       "switch4.go":      true, // error reported by noder (not running for types2 errorcheck test)
+       "typecheck.go":    true, // invalid function is not causing errors when called
+
+       "fixedbugs/bug176.go":    true, // types2 reports all errors (pref: types2)
+       "fixedbugs/bug193.go":    true, // types2 bug: shift error not reported (fixed in go/types)
+       "fixedbugs/bug195.go":    true, // types2 reports slightly different (but correct) bugs
+       "fixedbugs/bug213.go":    true, // error reported by noder (not running for types2 errorcheck test)
+       "fixedbugs/bug228.go":    true, // types2 not run after syntax errors
+       "fixedbugs/bug231.go":    true, // types2 bug? (same error reported twice)
+       "fixedbugs/bug255.go":    true, // types2 reports extra errors
+       "fixedbugs/bug351.go":    true, // types2 reports extra errors
+       "fixedbugs/bug374.go":    true, // types2 reports extra errors
+       "fixedbugs/bug385_32.go": true, // types2 doesn't produce "stack frame too large" error (32-bit specific)
+       "fixedbugs/bug385_64.go": true, // types2 doesn't produce "stack frame too large" error
+       "fixedbugs/bug388.go":    true, // types2 not run due to syntax errors
+       "fixedbugs/bug412.go":    true, // types2 produces a follow-on error
+
+       "fixedbugs/issue11362.go":  true, // types2 import path handling
+       "fixedbugs/issue11590.go":  true, // types2 doesn't report a follow-on error (pref: types2)
+       "fixedbugs/issue11610.go":  true, // types2 not run after syntax errors
+       "fixedbugs/issue11614.go":  true, // types2 reports an extra error
+       "fixedbugs/issue13415.go":  true, // declared but not used conflict
+       "fixedbugs/issue14520.go":  true, // missing import path error by types2
+       "fixedbugs/issue14540.go":  true, // error reported by noder (not running for types2 errorcheck test)
+       "fixedbugs/issue16428.go":  true, // types2 reports two instead of one error
+       "fixedbugs/issue17038.go":  true, // types2 doesn't report a follow-on error (pref: types2)
+       "fixedbugs/issue17645.go":  true, // multiple errors on same line
+       "fixedbugs/issue18393.go":  true, // types2 not run after syntax errors
+       "fixedbugs/issue19012.go":  true, // multiple errors on same line
+       "fixedbugs/issue20233.go":  true, // types2 reports two instead of one error (pref: compiler)
+       "fixedbugs/issue20245.go":  true, // types2 reports two instead of one error (pref: compiler)
+       "fixedbugs/issue20529.go":  true, // types2 doesn't produce "stack frame too large" error
+       "fixedbugs/issue20780.go":  true, // types2 doesn't produce "stack frame too large" error
+       "fixedbugs/issue21979.go":  true, // types2 doesn't report a follow-on error (pref: types2)
+       "fixedbugs/issue22200.go":  true, // types2 doesn't produce "stack frame too large" error
+       "fixedbugs/issue22200b.go": true, // types2 doesn't produce "stack frame too large" error
+       "fixedbugs/issue23732.go":  true, // types2 reports different (but ok) line numbers
+       "fixedbugs/issue25507.go":  true, // types2 doesn't produce "stack frame too large" error
+       "fixedbugs/issue25958.go":  true, // types2 doesn't report a follow-on error (pref: types2)
+       "fixedbugs/issue28079b.go": true, // types2 reports follow-on errors
+       "fixedbugs/issue28268.go":  true, // types2 reports follow-on errors
+       "fixedbugs/issue31747.go":  true, // types2 is missing support for -lang flag
+       "fixedbugs/issue33460.go":  true, // types2 reports alternative positions in separate error
+       "fixedbugs/issue34329.go":  true, // types2 is missing support for -lang flag
+       "fixedbugs/issue41575.go":  true, // types2 reports alternative positions in separate error
+       "fixedbugs/issue42058a.go": true, // types2 doesn't report "channel element type too large"
+       "fixedbugs/issue42058b.go": true, // types2 doesn't report "channel element type too large"
+       "fixedbugs/issue4232.go":   true, // types2 reports (correct) extra errors
+       "fixedbugs/issue4452.go":   true, // types2 reports (correct) extra errors
+       "fixedbugs/issue5609.go":   true, // types2 needs a better error message
+       "fixedbugs/issue6500.go":   true, // error reported by noder (not running for types2 errorcheck test)
+       "fixedbugs/issue6889.go":   true, // types2 can handle this without constant overflow
+       "fixedbugs/issue7525.go":   true, // types2 reports init cycle error on different line - ok otherwise
+       "fixedbugs/issue7525b.go":  true, // types2 reports init cycle error on different line - ok otherwise
+       "fixedbugs/issue7525c.go":  true, // types2 reports init cycle error on different line - ok otherwise
+       "fixedbugs/issue7525d.go":  true, // types2 reports init cycle error on different line - ok otherwise
+       "fixedbugs/issue7525e.go":  true, // types2 reports init cycle error on different line - ok otherwise
+       "fixedbugs/issue7742.go":   true, // types2 type-checking doesn't terminate
+       "fixedbugs/issue7746.go":   true, // types2 type-checking doesn't terminate
+}
index bccc9b53afc021950284370cc95834b9aae147d2..58a5eee70993089ed214592343fcbc71c915a9c6 100644 (file)
@@ -17,5 +17,5 @@ package main
 import "runtime"
 
 func main() {
-       runtime.printbool(true) // ERROR "unexported"
+       runtime.printbool(true) // ERROR "unexported|undefined"
 }
index 1309fdd56bde2f0ce0b8ce7222051a87f5c65a09..120ecbeccebce986363a45a194591e7d06e2b650 100644 (file)
@@ -17,12 +17,12 @@ func f() {
        _ = array[i:]
        _ = array[:j]
        _ = array[i:j]
-       _ = array[::] // ERROR "middle index required in 3-index slice" "final index required in 3-index slice"
-       _ = array[i::] // ERROR "middle index required in 3-index slice" "final index required in 3-index slice"
-       _ = array[:j:] // ERROR "final index required in 3-index slice"
-       _ = array[i:j:] // ERROR "final index required in 3-index slice"
-       _ = array[::k] // ERROR "middle index required in 3-index slice"
-       _ = array[i::k] // ERROR "middle index required in 3-index slice"
+       _ = array[::] // ERROR "middle index required in 3-index slice|invalid slice indices" "final index required in 3-index slice"
+       _ = array[i::] // ERROR "middle index required in 3-index slice|invalid slice indices" "final index required in 3-index slice"
+       _ = array[:j:] // ERROR "final index required in 3-index slice|invalid slice indices"
+       _ = array[i:j:] // ERROR "final index required in 3-index slice|invalid slice indices"
+       _ = array[::k] // ERROR "middle index required in 3-index slice|invalid slice indices"
+       _ = array[i::k] // ERROR "middle index required in 3-index slice|invalid slice indices"
        _ = array[:j:k]
        _ = array[i:j:k]
        
@@ -30,12 +30,12 @@ func f() {
        _ = slice[i:]
        _ = slice[:j]
        _ = slice[i:j]
-       _ = slice[::] // ERROR "middle index required in 3-index slice" "final index required in 3-index slice"
-       _ = slice[i::] // ERROR "middle index required in 3-index slice" "final index required in 3-index slice"
-       _ = slice[:j:] // ERROR "final index required in 3-index slice"
-       _ = slice[i:j:] // ERROR "final index required in 3-index slice"
-       _ = slice[::k] // ERROR "middle index required in 3-index slice"
-       _ = slice[i::k] // ERROR "middle index required in 3-index slice"
+       _ = slice[::] // ERROR "middle index required in 3-index slice|invalid slice indices" "final index required in 3-index slice"
+       _ = slice[i::] // ERROR "middle index required in 3-index slice|invalid slice indices" "final index required in 3-index slice"
+       _ = slice[:j:] // ERROR "final index required in 3-index slice|invalid slice indices"
+       _ = slice[i:j:] // ERROR "final index required in 3-index slice|invalid slice indices"
+       _ = slice[::k] // ERROR "middle index required in 3-index slice|invalid slice indices"
+       _ = slice[i::k] // ERROR "middle index required in 3-index slice|invalid slice indices"
        _ = slice[:j:k]
        _ = slice[i:j:k]
        
@@ -54,43 +54,43 @@ func f() {
 
        // check invalid indices
        _ = array[1:2]
-       _ = array[2:1] // ERROR "invalid slice index|inverted slice"
+       _ = array[2:1] // ERROR "invalid slice index|invalid slice indices|inverted slice"
        _ = array[2:2]
        _ = array[i:1]
        _ = array[1:j]
        _ = array[1:2:3]
-       _ = array[1:3:2] // ERROR "invalid slice index|inverted slice"
-       _ = array[2:1:3] // ERROR "invalid slice index|inverted slice"
-       _ = array[2:3:1] // ERROR "invalid slice index|inverted slice"
-       _ = array[3:1:2] // ERROR "invalid slice index|inverted slice"
-       _ = array[3:2:1] // ERROR "invalid slice index|inverted slice"
+       _ = array[1:3:2] // ERROR "invalid slice index|invalid slice indices|inverted slice"
+       _ = array[2:1:3] // ERROR "invalid slice index|invalid slice indices|inverted slice"
+       _ = array[2:3:1] // ERROR "invalid slice index|invalid slice indices|inverted slice"
+       _ = array[3:1:2] // ERROR "invalid slice index|invalid slice indices|inverted slice"
+       _ = array[3:2:1] // ERROR "invalid slice index|invalid slice indices|inverted slice"
        _ = array[i:1:2]
-       _ = array[i:2:1] // ERROR "invalid slice index|inverted slice"
+       _ = array[i:2:1] // ERROR "invalid slice index|invalid slice indices|inverted slice"
        _ = array[1:j:2]
-       _ = array[2:j:1] // ERROR "invalid slice index"
+       _ = array[2:j:1] // ERROR "invalid slice index|invalid slice indices"
        _ = array[1:2:k]
-       _ = array[2:1:k] // ERROR "invalid slice index|inverted slice"
+       _ = array[2:1:k] // ERROR "invalid slice index|invalid slice indices|inverted slice"
        
        _ = slice[1:2]
-       _ = slice[2:1] // ERROR "invalid slice index|inverted slice"
+       _ = slice[2:1] // ERROR "invalid slice index|invalid slice indices|inverted slice"
        _ = slice[2:2]
        _ = slice[i:1]
        _ = slice[1:j]
        _ = slice[1:2:3]
-       _ = slice[1:3:2] // ERROR "invalid slice index|inverted slice"
-       _ = slice[2:1:3] // ERROR "invalid slice index|inverted slice"
-       _ = slice[2:3:1] // ERROR "invalid slice index|inverted slice"
-       _ = slice[3:1:2] // ERROR "invalid slice index|inverted slice"
-       _ = slice[3:2:1] // ERROR "invalid slice index|inverted slice"
+       _ = slice[1:3:2] // ERROR "invalid slice index|invalid slice indices|inverted slice"
+       _ = slice[2:1:3] // ERROR "invalid slice index|invalid slice indices|inverted slice"
+       _ = slice[2:3:1] // ERROR "invalid slice index|invalid slice indices|inverted slice"
+       _ = slice[3:1:2] // ERROR "invalid slice index|invalid slice indices|inverted slice"
+       _ = slice[3:2:1] // ERROR "invalid slice index|invalid slice indices|inverted slice"
        _ = slice[i:1:2]
-       _ = slice[i:2:1] // ERROR "invalid slice index|inverted slice"
+       _ = slice[i:2:1] // ERROR "invalid slice index|invalid slice indices|inverted slice"
        _ = slice[1:j:2]
-       _ = slice[2:j:1] // ERROR "invalid slice index"
+       _ = slice[2:j:1] // ERROR "invalid slice index|invalid slice indices"
        _ = slice[1:2:k]
-       _ = slice[2:1:k] // ERROR "invalid slice index|inverted slice"
+       _ = slice[2:1:k] // ERROR "invalid slice index|invalid slice indices|inverted slice"
        
        _ = str[1:2]
-       _ = str[2:1] // ERROR "invalid slice index|inverted slice"
+       _ = str[2:1] // ERROR "invalid slice index|invalid slice indices|inverted slice"
        _ = str[2:2]
        _ = str[i:1]
        _ = str[1:j]
@@ -115,7 +115,7 @@ func f() {
        _ = slice[1:11]
        _ = slice[1:11:12]
        _ = slice[1:2:11]
-       _ = slice[1:11:3] // ERROR "invalid slice index"
-       _ = slice[11:2:3] // ERROR "invalid slice index|inverted slice"
+       _ = slice[1:11:3] // ERROR "invalid slice index|invalid slice indices"
+       _ = slice[11:2:3] // ERROR "invalid slice index|invalid slice indices|inverted slice"
        _ = slice[11:12:13]
 }
index 28705e464ef2c20949e7298fe1072a24fe2ab2df..403563223c7d11d7bbd82ace8e84e5d76538465f 100644 (file)
@@ -28,21 +28,21 @@ func bad() {
        var m, m1 map[int]int
        switch m {
        case nil:
-       case m1: // ERROR "can only compare map m to nil|map can only be compared to nil"
+       case m1: // ERROR "can only compare map m to nil|map can only be compared to nil|cannot compare"
        default:
        }
 
        var a, a1 []int
        switch a {
        case nil:
-       case a1: // ERROR "can only compare slice a to nil|slice can only be compared to nil"
+       case a1: // ERROR "can only compare slice a to nil|slice can only be compared to nil|cannot compare"
        default:
        }
 
        var f, f1 func()
        switch f {
        case nil:
-       case f1: // ERROR "can only compare func f to nil|func can only be compared to nil"
+       case f1: // ERROR "can only compare func f to nil|func can only be compared to nil|cannot compare"
        default:
        }
 
index ce95bf8d7b1b4f8c7328900ec18e64b50d091e00..dcf7ba0cf45f6b41b4136666fa5cb22e6ca0b4b7 100644 (file)
@@ -12,41 +12,41 @@ package main
 func f0(x int) {
        switch x {
        case 0:
-       case 0: // ERROR "duplicate case 0 in switch"
+       case 0: // ERROR "duplicate case (0 in switch)?"
        }
 
        switch x {
        case 0:
-       case int(0): // ERROR "duplicate case int.0. .value 0. in switch"
+       case int(0): // ERROR "duplicate case (int.0. .value 0. in switch)?"
        }
 }
 
 func f1(x float32) {
        switch x {
        case 5:
-       case 5: // ERROR "duplicate case 5 in switch"
-       case 5.0: // ERROR "duplicate case 5 in switch"
+       case 5: // ERROR "duplicate case (5 in switch)?"
+       case 5.0: // ERROR "duplicate case (5 in switch)?"
        }
 }
 
 func f2(s string) {
        switch s {
        case "":
-       case "": // ERROR "duplicate case .. in switch"
+       case "": // ERROR "duplicate case (.. in switch)?"
        case "abc":
-       case "abc": // ERROR "duplicate case .abc. in switch"
+       case "abc": // ERROR "duplicate case (.abc. in switch)?"
        }
 }
 
 func f3(e interface{}) {
        switch e {
        case 0:
-       case 0: // ERROR "duplicate case 0 in switch"
+       case 0: // ERROR "duplicate case (0 in switch)?"
        case int64(0):
        case float32(10):
-       case float32(10): // ERROR "duplicate case float32\(10\) .value 10. in switch"
+       case float32(10): // ERROR "duplicate case (float32\(10\) .value 10. in switch)?"
        case float64(10):
-       case float64(10): // ERROR "duplicate case float64\(10\) .value 10. in switch"
+       case float64(10): // ERROR "duplicate case (float64\(10\) .value 10. in switch)?"
        }
 }
 
@@ -82,13 +82,13 @@ func f7(a int) {
 func f8(r rune) {
        const x = 10
        switch r {
-       case 33, 33: // ERROR "duplicate case 33 in switch"
+       case 33, 33: // ERROR "duplicate case (33 in switch)?"
        case 34, '"': // ERROR "duplicate case '"' .value 34. in switch"
-       case 35, rune('#'): // ERROR "duplicate case rune.'#'. .value 35. in switch"
-       case 36, rune(36): // ERROR "duplicate case rune.36. .value 36. in switch"
-       case 37, '$'+1: // ERROR "duplicate case '\$' \+ 1 .value 37. in switch"
+       case 35, rune('#'): // ERROR "duplicate case (rune.'#'. .value 35. in switch)?"
+       case 36, rune(36): // ERROR "duplicate case (rune.36. .value 36. in switch)?"
+       case 37, '$'+1: // ERROR "duplicate case ('\$' \+ 1 .value 37. in switch)?"
        case 'b':
-       case 'a', 'b', 'c', 'd': // ERROR "duplicate case 'b' .value 98."
-       case x, x: // ERROR "duplicate case x .value 10."
+       case 'a', 'b', 'c', 'd': // ERROR "duplicate case ('b' .value 98.)?"
+       case x, x: // ERROR "duplicate case (x .value 10.)?"
        }
 }
index 9d102fef515d1cbfbe60ff8308b219e3ef479677..4f95d02615dbdb5b94adaf6d04d3b6b1b372f3af 100644 (file)
@@ -15,7 +15,7 @@ package main
 // Verify that type switch statements with impossible cases are detected by the compiler.
 func f0(e error) {
        switch e.(type) {
-       case int: // ERROR "impossible type switch case: e \(type error\) cannot have dynamic type int \(missing Error method\)"
+       case int: // ERROR "impossible type switch case: e \(type error\) cannot have dynamic type int \(missing Error method\)|impossible type assertion"
        }
 }
 
@@ -23,11 +23,11 @@ func f0(e error) {
 func f1(e interface{}) {
        switch e {
        default:
-       default: // ERROR "multiple defaults in switch"
+       default: // ERROR "multiple defaults( in switch)?"
        }
        switch e.(type) {
        default:
-       default: // ERROR "multiple defaults in switch"
+       default: // ERROR "multiple defaults( in switch)?"
        }
 }
 
@@ -41,6 +41,6 @@ func (*X) Foo() {}
 func f2() {
        var i I
        switch i.(type) {
-       case X: // ERROR "impossible type switch case: i \(type I\) cannot have dynamic type X \(Foo method has pointer receiver\)"
+       case X: // ERROR "impossible type switch case: i \(type I\) cannot have dynamic type X \(Foo method has pointer receiver\)|impossible type assertion"
        }
 }
index 75060669b33b05c68899bcc87f5ca059022d9303..3fb0129b15e2d35c0d0ad766d792d5562cc612d2 100644 (file)
@@ -27,7 +27,7 @@ func f4(e interface{}) {
        case struct {
                i int "tag2"
        }:
-       case struct { // ERROR "duplicate case struct { i int .tag1. } in type switch"
+       case struct { // ERROR "duplicate case struct { i int .tag1. } in type switch|duplicate case"
                i int "tag1"
        }:
        }
index 3b3e78858e033e61d93b3701b36e60fe979d5d2d..13f413cfc9288fd61fe8196415f66c6e8a9f7530 100644 (file)
@@ -9,6 +9,6 @@
 
 package main
 
-const A = 1 + B // ERROR "constant definition loop\n.*A uses B\n.*B uses C\n.*C uses A"
-const B = C - 1 // ERROR "constant definition loop\n.*B uses C\n.*C uses B"
+const A = 1 + B // ERROR "constant definition loop\n.*A uses B\n.*B uses C\n.*C uses A|initialization loop"
+const B = C - 1 // ERROR "constant definition loop\n.*B uses C\n.*C uses B|initialization loop"
 const C = A + B + 1
diff --git a/test/typeparam/importtest.go b/test/typeparam/importtest.go
new file mode 100644 (file)
index 0000000..9cb30e8
--- /dev/null
@@ -0,0 +1,16 @@
+// compile -G
+
+// Copyright 2020 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.
+
+// This file checks that basic importing works in -G mode.
+
+package p
+
+import "fmt"
+import "math"
+
+func f(x float64) {
+       fmt.Println(math.Sin(x))
+}
diff --git a/test/typeparam/smoketest.go b/test/typeparam/smoketest.go
new file mode 100644 (file)
index 0000000..b7d6201
--- /dev/null
@@ -0,0 +1,56 @@
+// compile -G
+
+// Copyright 2020 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.
+
+// This file checks simple code using type parameters.
+
+package smoketest
+
+// type parameters for functions
+func f1[P any]()
+func f2[P1, P2 any, P3 any]()
+func f3[P interface{}](x P, y T1[int])
+
+// function instantiations
+var _ = f1[int]
+var _ = f2[int, string, struct{}]
+var _ = f3[bool]
+
+// type parameters for types
+type T1[P any] struct{}
+type T2[P1, P2 any, P3 any] struct{}
+type T3[P interface{}] interface{}
+
+// type instantiations
+type _ T1[int]
+type _ T2[int, string, struct{}]
+type _ T3[bool]
+
+// methods
+func (T1[P]) m1() {}
+func (T1[_]) m2() {}
+func (x T2[P1, P2, P3]) m() {}
+
+// type lists
+type _ interface {
+       m1()
+       m2()
+       type int, float32, string
+       m3()
+}
+
+// embedded instantiated types
+type _ struct {
+       f1, f2 int
+       T1[int]
+       T2[int, string, struct{}]
+       T3[bool]
+}
+
+type _ interface {
+       m1()
+       m2()
+       T3[bool]
+}
diff --git a/test/typeparam/tparam1.go b/test/typeparam/tparam1.go
new file mode 100644 (file)
index 0000000..7043933
--- /dev/null
@@ -0,0 +1,42 @@
+// errorcheck -G
+
+// Copyright 2020 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.
+
+// Basic type parameter list type-checking (not syntax) errors.
+
+package tparam1
+
+// The predeclared identifier "any" is only visible as a constraint
+// in a type parameter list.
+var _ any // ERROR "undefined"
+func _(_ any) // ERROR "undefined"
+type _[_ any /* ok here */ ] struct{}
+
+const N = 10
+
+type (
+        _[] struct{} // slice
+        _[N] struct{} // array
+        _[T any] struct{}
+        _[T, T any] struct{} // ERROR "T redeclared"
+        _[T1, T2 any, T3 any] struct{}
+)
+
+func _[T any]()
+func _[T, T any]() // ERROR "T redeclared"
+func _[T1, T2 any](x T1) T2
+
+// Type parameters are visible from opening [ to end of function.
+type C interface{}
+
+func _[T interface{}]()
+func _[T C]()
+func _[T struct{}]() // ERROR "not an interface"
+func _[T interface{ m() T }]()
+func _[T1 interface{ m() T2 }, T2 interface{ m() T1 }]() {
+        var _ T1
+}
+
+// TODO(gri) expand this
index 138818756672dac8f08aafe2e4aef28d39aedbc0..a57889bc1dee4f66dd7276e746812f8dd6817938 100644 (file)
@@ -36,13 +36,13 @@ func main() {
        }
 
        // Issue 2827.
-       switch _ := r.(type) { // ERROR "invalid variable name _|no new variables"
+       switch _ := r.(type) { // ERROR "invalid variable name _|no new variables?"
        }
 }
 
 func noninterface() {
        var i int
-       switch i.(type) { // ERROR "cannot type switch on non-interface value"
+       switch i.(type) { // ERROR "cannot type switch on non-interface value|not an interface type"
        case string:
        case int:
        }
@@ -51,6 +51,6 @@ func noninterface() {
                name string
        }
        var s S
-       switch s.(type) { // ERROR "cannot type switch on non-interface value"
+       switch s.(type) { // ERROR "cannot type switch on non-interface value|not an interface type"
        }
 }
index 5c7aad24a6ca241bd4dfdc89a8fa1ba3f5db69b1..a3f0e1270befedfe73ce5bfdd78f52ea5ba50bde 100644 (file)
@@ -42,102 +42,103 @@ var m map[int]int
 
 func _() {
        // Note: if the next line changes to x, the error silences the x+x etc below!
-       x1 // ERROR "x1 evaluated but not used"
+       x1 // ERROR "x1 .* not used"
 
-       nil                    // ERROR "nil evaluated but not used"
-       C                      // ERROR  "C evaluated but not used"
-       1                      // ERROR "1 evaluated but not used"
-       x + x                  // ERROR "x \+ x evaluated but not used"
-       x - x                  // ERROR "x - x evaluated but not used"
-       x | x                  // ERROR "x \| x evaluated but not used"
-       "a" + s                // ERROR ".a. \+ s evaluated but not used"
-       &x                     // ERROR "&x evaluated but not used"
-       b && b                 // ERROR "b && b evaluated but not used"
-       append(slice, 1)       // ERROR "append\(slice, 1\) evaluated but not used"
-       string(bytes)          // ERROR "string\(bytes\) evaluated but not used"
-       string(runes)          // ERROR "string\(runes\) evaluated but not used"
+       nil                    // ERROR "nil .* not used"
+       C                      // ERROR  "C .* not used"
+       1                      // ERROR "1 .* not used"
+       x + x                  // ERROR "x \+ x .* not used"
+       x - x                  // ERROR "x - x .* not used"
+       x | x                  // ERROR "x \| x .* not used"
+       "a" + s                // ERROR ".a. \+ s .* not used"
+       &x                     // ERROR "&x .* not used"
+       b && b                 // ERROR "b && b .* not used"
+       append(slice, 1)       // ERROR "append\(slice, 1\) .* not used"
+       string(bytes)          // ERROR "string\(bytes\) .* not used"
+       string(runes)          // ERROR "string\(runes\) .* not used"
        f0()                   // ok
        f1()                   // ok
        f2()                   // ok
-       _ = f0()               // ERROR "f0\(\) used as value"
+       _ = f0()               // ERROR "f0\(\) .*used as value"
        _ = f1()               // ok
        _, _ = f2()            // ok
-       _ = f2()               // ERROR "assignment mismatch: 1 variable but f2 returns 2 values"
-       T.M0                   // ERROR "T.M0 evaluated but not used"
-       t.M0                   // ERROR "t.M0 evaluated but not used"
-       cap                    // ERROR "use of builtin cap not in function call"
-       cap(slice)             // ERROR "cap\(slice\) evaluated but not used"
+       _ = f2()               // ERROR "assignment mismatch: 1 variable but f2 returns 2 values|cannot assign"
+       T.M0                   // ERROR "T.M0 .* not used"
+       t.M0                   // ERROR "t.M0 .* not used"
+       cap                    // ERROR "use of builtin cap not in function call|must be called"
+       cap(slice)             // ERROR "cap\(slice\) .* not used"
        close(c)               // ok
-       _ = close(c)           // ERROR "close\(c\) used as value"
-       func() {}              // ERROR "func literal evaluated but not used"
+       _ = close(c)           // ERROR "close\(c\) .*used as value"
+       func() {}              // ERROR "func literal .* not used|is not used"
        X{}                    // ERROR "undefined: X"
-       map[string]int{}       // ERROR "map\[string\]int{} evaluated but not used"
-       struct{}{}             // ERROR "struct ?{}{} evaluated but not used"
-       [1]int{}               // ERROR "\[1\]int{} evaluated but not used"
-       []int{}                // ERROR "\[\]int{} evaluated but not used"
-       &struct{}{}            // ERROR "&struct ?{}{} evaluated but not used"
-       float32(x)             // ERROR "float32\(x\) evaluated but not used"
-       I(t)                   // ERROR "I\(t\) evaluated but not used"
-       int(x)                 // ERROR "int\(x\) evaluated but not used"
+       map[string]int{}       // ERROR "map\[string\]int{} .* not used"
+       struct{}{}             // ERROR "struct ?{}{} .* not used"
+       [1]int{}               // ERROR "\[1\]int{} .* not used"
+       []int{}                // ERROR "\[\]int{} .* not used"
+       &struct{}{}            // ERROR "&struct ?{}{} .* not used"
+       float32(x)             // ERROR "float32\(x\) .* not used"
+       I(t)                   // ERROR "I\(t\) .* not used"
+       int(x)                 // ERROR "int\(x\) .* not used"
        copy(slice, slice)     // ok
        _ = copy(slice, slice) // ok
        delete(m, 1)           // ok
-       _ = delete(m, 1)       // ERROR "delete\(m, 1\) used as value"
-       t.X                    // ERROR "t.X evaluated but not used"
-       tp.X                   // ERROR "tp.X evaluated but not used"
-       t.M                    // ERROR "t.M evaluated but not used"
-       I.M                    // ERROR "I.M evaluated but not used"
-       i.(T)                  // ERROR "i.\(T\) evaluated but not used"
-       x == x                 // ERROR "x == x evaluated but not used"
-       x != x                 // ERROR "x != x evaluated but not used"
-       x != x                 // ERROR "x != x evaluated but not used"
-       x < x                  // ERROR "x < x evaluated but not used"
-       x >= x                 // ERROR "x >= x evaluated but not used"
-       x > x                  // ERROR "x > x evaluated but not used"
-       *tp                    // ERROR "\*tp evaluated but not used"
-       slice[0]               // ERROR "slice\[0\] evaluated but not used"
-       m[1]                   // ERROR "m\[1\] evaluated but not used"
-       len(slice)             // ERROR "len\(slice\) evaluated but not used"
-       make(chan int)         // ERROR "make\(chan int\) evaluated but not used"
-       make(map[int]int)      // ERROR "make\(map\[int\]int\) evaluated but not used"
-       make([]int, 1)         // ERROR "make\(\[\]int, 1\) evaluated but not used"
-       x * x                  // ERROR "x \* x evaluated but not used"
-       x / x                  // ERROR "x / x evaluated but not used"
-       x % x                  // ERROR "x % x evaluated but not used"
-       x << x                 // ERROR "x << x evaluated but not used"
-       x >> x                 // ERROR "x >> x evaluated but not used"
-       x & x                  // ERROR "x & x evaluated but not used"
-       x &^ x                 // ERROR "x &\^ x evaluated but not used"
-       new(int)               // ERROR "new\(int\) evaluated but not used"
-       !b                     // ERROR "!b evaluated but not used"
-       ^x                     // ERROR "\^x evaluated but not used"
-       +x                     // ERROR "\+x evaluated but not used"
-       -x                     // ERROR "-x evaluated but not used"
-       b || b                 // ERROR "b \|\| b evaluated but not used"
+       _ = delete(m, 1)       // ERROR "delete\(m, 1\) .*used as value"
+       t.X                    // ERROR "t.X .* not used"
+       tp.X                   // ERROR "tp.X .* not used"
+       t.M                    // ERROR "t.M .* not used"
+       I.M                    // ERROR "I.M .* not used"
+       i.(T)                  // ERROR "i.\(T\) .* not used"
+       x == x                 // ERROR "x == x .* not used"
+       x != x                 // ERROR "x != x .* not used"
+       x != x                 // ERROR "x != x .* not used"
+       x < x                  // ERROR "x < x .* not used"
+       x >= x                 // ERROR "x >= x .* not used"
+       x > x                  // ERROR "x > x .* not used"
+       *tp                    // ERROR "\*tp .* not used"
+       slice[0]               // ERROR "slice\[0\] .* not used"
+       m[1]                   // ERROR "m\[1\] .* not used"
+       len(slice)             // ERROR "len\(slice\) .* not used"
+       make(chan int)         // ERROR "make\(chan int\) .* not used"
+       make(map[int]int)      // ERROR "make\(map\[int\]int\) .* not used"
+       make([]int, 1)         // ERROR "make\(\[\]int, 1\) .* not used"
+       x * x                  // ERROR "x \* x .* not used"
+       x / x                  // ERROR "x / x .* not used"
+       x % x                  // ERROR "x % x .* not used"
+       x << x                 // ERROR "x << x .* not used"
+       x >> x                 // ERROR "x >> x .* not used"
+       x & x                  // ERROR "x & x .* not used"
+       x &^ x                 // ERROR "x &\^ x .* not used"
+       new(int)               // ERROR "new\(int\) .* not used"
+       !b                     // ERROR "!b .* not used"
+       ^x                     // ERROR "\^x .* not used"
+       +x                     // ERROR "\+x .* not used"
+       -x                     // ERROR "-x .* not used"
+       b || b                 // ERROR "b \|\| b .* not used"
        panic(1)               // ok
-       _ = panic(1)           // ERROR "panic\(1\) used as value"
+       _ = panic(1)           // ERROR "panic\(1\) .*used as value"
        print(1)               // ok
-       _ = print(1)           // ERROR "print\(1\) used as value"
+       _ = print(1)           // ERROR "print\(1\) .*used as value"
        println(1)             // ok
-       _ = println(1)         // ERROR "println\(1\) used as value"
+       _ = println(1)         // ERROR "println\(1\) .*used as value"
        c <- 1                 // ok
-       slice[1:1]             // ERROR "slice\[1:1\] evaluated but not used"
-       array[1:1]             // ERROR "array\[1:1\] evaluated but not used"
-       s[1:1]                 // ERROR "s\[1:1\] evaluated but not used"
-       slice[1:1:1]           // ERROR "slice\[1:1:1\] evaluated but not used"
-       array[1:1:1]           // ERROR "array\[1:1:1\] evaluated but not used"
+       slice[1:1]             // ERROR "slice\[1:1\] .* not used"
+       array[1:1]             // ERROR "array\[1:1\] .* not used"
+       s[1:1]                 // ERROR "s\[1:1\] .* not used"
+       slice[1:1:1]           // ERROR "slice\[1:1:1\] .* not used"
+       array[1:1:1]           // ERROR "array\[1:1:1\] .* not used"
        recover()              // ok
        <-c                    // ok
-       string(r)              // ERROR "string\(r\) evaluated but not used"
-       iota                   // ERROR "undefined: iota"
-       real(cp)               // ERROR "real\(cp\) evaluated but not used"
-       imag(cp)               // ERROR "imag\(cp\) evaluated but not used"
-       complex(1, 2)          // ERROR "complex\(1, 2\) evaluated but not used"
-       unsafe.Alignof(t.X)    // ERROR "unsafe.Alignof\(t.X\) evaluated but not used"
-       unsafe.Offsetof(t.X)   // ERROR "unsafe.Offsetof\(t.X\) evaluated but not used"
-       unsafe.Sizeof(t)       // ERROR "unsafe.Sizeof\(t\) evaluated but not used"
-       _ = int                // ERROR "type int is not an expression"
-       (x)                    // ERROR "x evaluated but not used"
-       _ = new(x2)            // ERROR "x2 is not a type"
-       _ = new(1 + 1)         // ERROR "1 \+ 1 is not a type"
+       string(r)              // ERROR "string\(r\) .* not used"
+       iota                   // ERROR "undefined: iota|cannot use iota"
+       real(cp)               // ERROR "real\(cp\) .* not used"
+       imag(cp)               // ERROR "imag\(cp\) .* not used"
+       complex(1, 2)          // ERROR "complex\(1, 2\) .* not used"
+       unsafe.Alignof(t.X)    // ERROR "unsafe.Alignof\(t.X\) .* not used"
+       unsafe.Offsetof(t.X)   // ERROR "unsafe.Offsetof\(t.X\) .* not used"
+       unsafe.Sizeof(t)       // ERROR "unsafe.Sizeof\(t\) .* not used"
+       _ = int                // ERROR "type int is not an expression|not an expression"
+       (x)                    // ERROR "x .* not used|not used"
+       _ = new(x2)            // ERROR "x2 is not a type|not a type"
+       // Disabled due to issue #43125.
+       // _ = new(1 + 1)         // DISABLED "1 \+ 1 is not a type"
 }
index 82ab814197dc6f135783ba40cb7dc66a412c5053..349cc8b4e3b546ba971a42116ae2d2262c2ac932 100644 (file)
@@ -12,6 +12,6 @@ package main
 func main() {
        _ = asdf        // ERROR "undefined.*asdf"
 
-       new = 1 // ERROR "use of builtin new not in function call|invalid left hand side"
+       new = 1 // ERROR "use of builtin new not in function call|invalid left hand side|must be called"
 }