diff --git a/CONTRIBUTORS b/CONTRIBUTORS index e2e102f610..48567eed15 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -120,6 +120,7 @@ Alex Kohler Alex Myasoedov Alex Opie Alex Plugaru +Alex Schade <39062967+aschade92@users.noreply.github.com> Alex Schroeder Alex Sergeyev Alex Tokarev @@ -135,6 +136,7 @@ Alexander Klauer Alexander Kucherenko Alexander Larsson Alexander Lourier +Alexander Melentyev Alexander Menzhinsky Alexander Morozov Alexander Neumann @@ -145,6 +147,7 @@ Alexander Polcyn Alexander Rakoczy Alexander Reece Alexander Surma +Alexander Yastrebov Alexander Zhavnerchik Alexander Zillion Alexander Zolotov @@ -179,6 +182,7 @@ Alok Menghrajani Alwin Doss Aman Gupta Amarjeet Anand +Amelia Downs Amir Mohammad Saied Amit Kumar Amr Mohammed @@ -191,6 +195,7 @@ Anatol Pomozov Anders Pearson Anderson Queiroz André Carvalho +Andre Marianiello André Martins Andre Nathan Andrea Nodari @@ -221,6 +226,7 @@ Andrew Gerrand Andrew Harding Andrew Jackura Andrew Kemm +Andrew LeFevre Andrew Louis Andrew Lutomirski Andrew Medvedev @@ -234,6 +240,7 @@ Andrew Stormont Andrew Stribblehill Andrew Szeto Andrew Todd +Andrew Wansink Andrew Werner Andrew Wilkins Andrew Williams @@ -283,6 +290,7 @@ Antonio Bibiano Antonio Garcia Antonio Huete Jimenez Antonio Murdaca +Antonio Ojea Antonio Troina Anze Kolar Aofei Sheng @@ -290,6 +298,7 @@ Apisak Darakananda Aram Hăvărneanu Araragi Hokuto Arash Bina +Archana Ravindar Arda Güçlü Areski Belaid Ariel Mashraki @@ -299,6 +308,7 @@ Arnaud Ysmal Arne Hormann Arnout Engelen Aron Nopanen +Arran Walker Artem Alekseev Artem Khvastunov Artem Kolin @@ -337,6 +347,7 @@ Balaram Makam Balazs Lecz Baokun Lee Barnaby Keene +Bartłomiej Klimczak Bartosz Grzybowski Bartosz Oler Bassam Ojeil @@ -368,6 +379,7 @@ Benny Siegert Benoit Sigoure Berengar Lehr Berkant Ipek <41230766+0xbkt@users.noreply.github.com> +Beth Brown Bharath Kumar Uppala Bharath Thiruveedula Bhavin Gandhi @@ -430,6 +442,7 @@ Brian Ketelsen Brian Slesinsky Brian Smith Brian Starke +Bruce Huang Bryan Alexander Bryan Boreham Bryan C. Mills @@ -482,17 +495,21 @@ Charles Kenney Charles L. Dorian Charles Lee Charles Weill +Charlie Getzen Charlie Moog Charlotte Brandhorst-Satzkorn Chauncy Cullitan Chen Zhidong Chen Zhihan +Cheng Wang Cherry Mui Chew Choon Keat +Chia-Chi Hsu Chiawen Chen Chirag Sukhala Cholerae Hu Chotepud Teo +Chressie Himpel Chris Ball Chris Biscardi Chris Broadfoot @@ -570,6 +587,7 @@ Cuong Manh Le Curtis La Graff Cyrill Schumacher Dai Jie +Dai Wentao Daisuke Fujita Daisuke Suzuki Daker Fernandes Pinheiro @@ -603,6 +621,7 @@ Daniel Langner Daniel Lidén Daniel Lublin Daniel Mangum +Daniel Marshall Daniel Martí Daniel McCarney Daniel Morsing @@ -727,6 +746,7 @@ Dmitry Mottl Dmitry Neverov Dmitry Savintsev Dmitry Yakunin +Dmytro Shynkevych Doga Fincan Domas Tamašauskas Domen Ipavec @@ -751,6 +771,7 @@ Dustin Herbison Dustin Long Dustin Sallings Dustin Shields-Cloues +Dustin Spicuzza Dvir Volk Dylan Waits Ed Schouten @@ -810,9 +831,11 @@ Erin Masatsugu Ernest Chiang Erwin Oegema Esko Luontola +Ethan Anderson Ethan Burns Ethan Hur Ethan Miller +Ethan Reesor Euan Kemp Eugene Formanenko Eugene Kalinin @@ -831,8 +854,10 @@ Evgeniy Polyakov Ewan Chou Ewan Valentine Eyal Posener +F. Talha Altınel Fabian Wickborn Fabian Zaremba +Fabio Falzoi Fabrizio Milo Faiyaz Ahmed Fan Hongjian @@ -861,21 +886,25 @@ Firmansyah Adiputra Florian Forster Florian Uekermann Florian Weimer +Florin Papa Florin Patan Folke Behrens Ford Hurley +Forest Johnson Francesc Campoy Francesco Guardiani Francesco Renzi Francisco Claude Francisco Rojas Francisco Souza +Frank Chiarulli Jr Frank Schroeder Frank Somers Frederic Guillot Frederick Kelly Mayle III Frederik Ring Frederik Zipp +Frediano Ziglio Fredrik Enestad Fredrik Forsmo Fredrik Wallgren @@ -914,6 +943,7 @@ Geon Kim Georg Reinke George Gkirtsou George Hartzell +George Looshch George Shammas George Tsilias Gerasimos (Makis) Maropoulos @@ -954,19 +984,27 @@ GitHub User @fatedier (7346661) GitHub User @frennkie (6499251) GitHub User @geedchin (11672310) GitHub User @GrigoriyMikhalkin (3637857) +GitHub User @Gusted (25481501) GitHub User @hengwu0 (41297446) <41297446+hengwu0@users.noreply.github.com> GitHub User @hitzhangjie (3725760) +GitHub User @hkhere (33268704) <33268704+hkhere@users.noreply.github.com> +GitHub User @hopehook (7326168) GitHub User @hqpko (13887251) +GitHub User @Illirgway (5428603) GitHub User @itchyny (375258) GitHub User @jinmiaoluo (39730824) GitHub User @jopbrown (6345470) GitHub User @kazyshr (30496953) GitHub User @kc1212 (1093806) GitHub User @komisan19 (18901496) +GitHub User @korzhao (64203902) GitHub User @Kropekk (13366453) +GitHub User @lgbgbl (65756378) GitHub User @lhl2617 (33488131) GitHub User @linguohua (3434367) +GitHub User @lloydchang (1329685) GitHub User @LotusFenn (13775899) +GitHub User @luochuanhang (96416201) GitHub User @ly303550688 (11519839) GitHub User @madiganz (18340029) GitHub User @maltalex (10195391) @@ -976,6 +1014,7 @@ GitHub User @micnncim (21333876) GitHub User @mkishere (224617) <224617+mkishere@users.noreply.github.com> GitHub User @nu50218 (40682920) GitHub User @OlgaVlPetrova (44112727) +GitHub User @pierwill (19642016) GitHub User @pityonline (438222) GitHub User @po3rin (29445112) GitHub User @pokutuna (57545) @@ -983,13 +1022,18 @@ GitHub User @povsister (11040951) GitHub User @pytimer (17105586) GitHub User @qcrao (7698088) GitHub User @ramenjuniti (32011829) +GitHub User @renthraysk (30576707) +GitHub User @roudkerk (52280478) GitHub User @saitarunreddy (21041941) GitHub User @SataQiu (9354727) +GitHub User @seifchen (23326132) GitHub User @shogo-ma (9860598) GitHub User @sivchari (55221074) GitHub User @skanehira (7888591) GitHub User @soolaugust (10558124) GitHub User @surechen (7249331) +GitHub User @syumai (6882878) +GitHub User @tangxi666 (48145175) GitHub User @tatsumack (4510569) GitHub User @tell-k (26263) GitHub User @tennashi (10219626) @@ -999,6 +1043,7 @@ GitHub User @unbyte (5772358) GitHub User @uropek (39370426) GitHub User @utkarsh-extc (53217283) GitHub User @witchard (4994659) +GitHub User @wmdngngng (22067700) GitHub User @wolf1996 (5901874) GitHub User @yah01 (12216890) GitHub User @yuanhh (1298735) @@ -1029,12 +1074,14 @@ Guilherme Garnier Guilherme Goncalves Guilherme Rezende Guilherme Souza <32180229+gqgs@users.noreply.github.com> +Guillaume Blaquiere Guillaume J. Charmes Guillaume Sottas Günther Noack Guobiao Mei Guodong Li Guoliang Wang +Guoqi Chen Gustav Paul Gustav Westling Gustavo Franco @@ -1050,6 +1097,8 @@ Hang Qian Hanjun Kim Hanlin He Hanlin Shi +Hans Nielsen +Hao Mou Haoran Luo Haosdent Huang Harald Nordgren @@ -1126,6 +1175,7 @@ Igor Zhilianin Ikko Ashimine Illya Yalovyy Ilya Chukov <56119080+Elias506@users.noreply.github.com> +Ilya Mateyko Ilya Sinelnikov Ilya Tocar INADA Naoki @@ -1157,6 +1207,7 @@ Jaana Burcu Dogan Jaap Aarts Jack Britton Jack Lindamood +Jack You Jacob Baskin Jacob Blain Christen Jacob H. Haven @@ -1165,6 +1216,7 @@ Jacob Walker Jaden Teng Jae Kwon Jake B +Jake Ciolek Jakob Borg Jakob Weisblat Jakub Čajka @@ -1183,6 +1235,7 @@ James Eady James Fennell James Fysh James Gray +James Harris James Hartig James Kasten James Lawrence @@ -1246,6 +1299,7 @@ Jean de Klerk Jean-André Santoni Jean-François Bustarret Jean-Francois Cantin +Jean-Hadrien Chabran Jean-Marc Eurin Jean-Nicolas Moal Jed Denlea @@ -1260,6 +1314,7 @@ Jeff Johnson Jeff R. Allen Jeff Sickel Jeff Wendling +Jeff Wentworth Jeff Widman Jeffrey H Jelte Fennema @@ -1282,6 +1337,7 @@ Jesús Espino Jia Zhan Jiacai Liu Jiahao Lu +Jiahua Wang Jianing Yu Jianqiao Li Jiayu Yi @@ -1298,10 +1354,12 @@ Jingcheng Zhang Jingguo Yao Jingnan Si Jinkun Zhang +Jinwen Wo Jiong Du Jirka Daněk Jiulong Wang Joakim Sernbrant +Jochen Weber Joe Bowbeer Joe Cortopassi Joe Farrell @@ -1324,6 +1382,7 @@ Johan Euphrosine Johan Jansson Johan Knutzen Johan Sageryd +Johannes Altmanninger Johannes Huning John Asmuth John Bampton @@ -1338,10 +1397,12 @@ John Howard Palevich John Jago John Jeffery John Jenkins +John Kelly John Leidegren John McCabe John Moore John Newlin +John Olheiser John Papandriopoulos John Potocny John R. Lenton @@ -1382,6 +1443,7 @@ Jordan Rupprecht Jordi Martin Jorge Araya Jorge L. Fatta +Jorge Troncoso Jos Visser Josa Gesell Jose Luis Vázquez González @@ -1508,6 +1570,7 @@ Keyuan Li Kezhu Wang Khosrow Moossavi Kieran Colford +Kieran Gorman Kim Shrier Kim Yongbin Kir Kolyshkin @@ -1577,6 +1640,7 @@ Leonel Quinteros Lev Shamardin Lewin Bormann Lewis Waddicor +Li-Yu Yu Liam Haworth Lily Chung Lingchao Xin @@ -1657,7 +1721,9 @@ Mark Adams Mark Bucciarelli Mark Dain Mark Glines +Mark Hansen Mark Harrison +Mark Jeffery Mark Percival Mark Pulford Mark Rushakoff @@ -1686,7 +1752,7 @@ Martin Hoefling Martin Kreichgauer Martin Kunc Martin Lindhe -Martin Möhrmann +Martin Möhrmann Martin Neubauer Martin Olsen Martin Olsson @@ -1741,6 +1807,7 @@ Matthew Denton Matthew Holt Matthew Horsnell Matthew Waters +Matthias Dötsch Matthias Frei Matthieu Hauglustaine Matthieu Olivier @@ -1814,6 +1881,7 @@ Michal Bohuslávek Michal Cierniak Michał Derkacz Michal Franc +Michal Hruby Michał Łowicki Michal Pristas Michal Rostecki @@ -1844,6 +1912,7 @@ Mike Solomon Mike Strosaker Mike Tsao Mike Wiacek +Mikhail Faraponov <11322032+moredure@users.noreply.github.com> Mikhail Fesenko Mikhail Gusarov Mikhail Panchenko @@ -1870,6 +1939,7 @@ Moritz Fain Moriyoshi Koizumi Morten Siebuhr Môshe van der Sterre +Mostafa Solati Mostyn Bramley-Moore Mrunal Patel Muhammad Falak R Wani @@ -1927,6 +1997,7 @@ Nick Miyake Nick Patavalis Nick Petroni Nick Robinson +Nick Sherron Nick Smolin Nicolas BRULEZ Nicolas Kaiser @@ -1956,6 +2027,7 @@ Noah Santschi-Cooney Noble Johnson Nodir Turakulov Noel Georgi +Nooras Saba Norberto Lopes Norman B. Lancaster Nuno Cruces @@ -1973,6 +2045,7 @@ Oliver Tan Oliver Tonnhofer Olivier Antoine Olivier Duperray +Olivier Mengué Olivier Poitrey Olivier Saingre Olivier Wulveryck @@ -1982,6 +2055,7 @@ Ori Bernstein Ori Rawlings Oryan Moshe Osamu TONOMORI +Oscar Söderlund Özgür Kesim Pablo Caderno Pablo Lalloni @@ -2014,6 +2088,7 @@ Patrick Pelletier Patrick Riley Patrick Smith Patrik Lundin +Patrik Nyblom Paul A Querna Paul Borman Paul Boyd @@ -2042,6 +2117,7 @@ Paul Wankadia Paulo Casaretto Paulo Flabiano Smorigo Paulo Gomes +Pavel Kositsyn Pavel Paulau Pavel Watson Pavel Zinovkin @@ -2049,6 +2125,7 @@ Pavlo Sumkin Pawel Knap Pawel Szczur Paweł Szulik +Pedro Lopez Mareque Pei Xian Chee Pei-Ming Wu Pen Tree @@ -2164,6 +2241,7 @@ Rhys Hiltner Ricardo Padilha Ricardo Pchevuzinske Katz Ricardo Seriani +Rich Hong Richard Barnes Richard Crowley Richard Dingwall @@ -2179,6 +2257,7 @@ Rick Hudson Rick Sayre Rijnard van Tonder Riku Voipio +Riley Avron Risto Jaakko Saarelma Rob Earhart Rob Findley @@ -2186,8 +2265,10 @@ Rob Norman Rob Phoenix Rob Pike Robert Ayrapetyan +Robert Burke Robert Daniel Kortschak Robert Dinu +Robert Engels Robert Figueiredo Robert Griesemer Robert Hencke @@ -2212,6 +2293,7 @@ Roger Peppe Rohan Challa Rohan Verma Rohith Ravi +Roi Martin Roland Illig Roland Shoemaker Romain Baugue @@ -2242,6 +2324,7 @@ Ryan Canty Ryan Dahl Ryan Hitchman Ryan Kohler +Ryan Leung Ryan Lower Ryan Roden-Corrent Ryan Seys @@ -2275,6 +2358,7 @@ Sami Pönkänen Samuel Kelemen Samuel Tan Samuele Pedroni +San Ye Sander van Harmelen Sanjay Menakuru Santhosh Kumar Tekuri @@ -2339,6 +2423,7 @@ Shaba Abhiram Shahar Kohanim Shailesh Suryawanshi Shamil Garatuev +Shamim Akhtar Shane Hansen Shang Jian Ding Shaozhen Ding @@ -2375,6 +2460,7 @@ Simon Drake Simon Ferquel Simon Frei Simon Jefford +Simon Law Simon Rawet Simon Rozman Simon Ser @@ -2440,6 +2526,7 @@ Suharsh Sivakumar Sukrit Handa Sunny Suriyaa Sundararuban +Suvaditya Sur Suyash Suzy Mueller Sven Almgren @@ -2502,6 +2589,7 @@ Thomas Symborski Thomas Wanielista Thorben Krueger Thordur Bjornsson +Tiago Peczenyj Tiago Queiroz Tianji Wu Tianon Gravi @@ -2636,6 +2724,7 @@ Vladimir Varankin Vojtech Bocek Volker Dobler Volodymyr Paprotski +Vyacheslav Pachkov W. Trevor King Wade Simmons Wagner Riffel @@ -2653,6 +2742,7 @@ Wei Guangjing Wei Xiao Wei Xikai Weichao Tang +Weilu Jia Weixie Cui <523516579@qq.com> Wembley G. Leach, Jr Wenlei (Frank) He @@ -2722,9 +2812,11 @@ Yuichi Nishiwaki Yuji Yaginuma Yuki Ito Yuki OKUSHI +Yuki Osaki Yuki Yugui Sonoda Yukihiro Nishinaka <6elpinal@gmail.com> YunQiang Su +Yuntao Wang Yury Smolsky Yusuke Kagiwada Yuusei Kuwana @@ -2736,7 +2828,9 @@ Zach Gershman Zach Hoffman Zach Jones Zachary Amsden +Zachary Burkett Zachary Gershman +Zaiyang Li Zak Zakatell Kanda Zellyn Hunter @@ -2745,6 +2839,7 @@ Zhang Boyang Zheng Dayu Zheng Xu Zhengyu He +Zhi Zheng Zhongpeng Lin Zhongtao Chen Zhongwei Yao diff --git a/doc/go1.18.html b/doc/go1.18.html index c75bfe9e5d..b320579c37 100644 --- a/doc/go1.18.html +++ b/doc/go1.18.html @@ -84,7 +84,7 @@ Do not send CLs removing the interior tags from such phrases.
  • The new predeclared identifier - comparable is an interface the denotes the set of all types which can be + comparable is an interface that denotes the set of all types which can be compared using == or !=. It may only be used as (or embedded in) a type constraint.
  • @@ -135,9 +135,19 @@ Do not send CLs removing the interior tags from such phrases. the predeclared functions real, imag, and complex. We hope to remove this restriction in Go 1.19. +
  • + The Go compiler currently only supports calling a method m on a value + x of type parameter type P if m is explicitly + declared by P's constraint interface. + Similarly, method values x.m and method expressions + P.m also are only supported if m is explicitly + declared by P, even though m might be in the method set + of P by virtue of the fact that all types in P implement + m. We hope to remove this restriction in Go 1.19. +
  • Embedding a type parameter, or a pointer to a type parameter, as - an unnamed field in a struct type is not permitted. Similarly + an unnamed field in a struct type is not permitted. Similarly, embedding a type parameter in an interface type is not permitted. Whether these will ever be permitted is unclear at present.
  • @@ -182,7 +192,7 @@ Do not send CLs removing the interior tags from such phrases.

    Go 1.18 introduces the new GOAMD64 environment variable, which selects at compile time - a mininum target version of the AMD64 architecture. Allowed values are v1, + a minimum target version of the AMD64 architecture. Allowed values are v1, v2, v3, or v4. Each higher level requires, and takes advantage of, additional processor features. A detailed description can be found @@ -199,6 +209,12 @@ Do not send CLs removing the interior tags from such phrases. now supports the c-archive and c-shared build modes.

    +

    Linux

    + +

    + Go 1.18 requires Linux kernel version 2.6.32 or later. +

    +

    Windows

    @@ -250,6 +266,8 @@ Do not send CLs removing the interior tags from such phrases.

    Go command

    +

    go get

    +

    go get no longer builds or installs packages in module-aware mode. go get is now dedicated to @@ -269,9 +287,25 @@ Do not send CLs removing the interior tags from such phrases. and installs packages, as before.

    +

    Automatic go.mod and go.sum updates

    + +

    + The go mod graph, + go mod vendor, + go mod verify, and + go mod why subcommands + no longer automatically update the go.mod and + go.sum files. + (Those files can be updated explicitly using go get, + go mod tidy, or + go mod download.) +

    + +

    go version

    +

    The go command now embeds version control information in - binaries including the currently checked-out revision, commit time, and a + binaries. It includes the currently checked-out revision, commit time, and a flag indicating whether edited or untracked files are present. Version control information is embedded if the go command is invoked in a directory within a Git, Mercurial, Fossil, or Bazaar repository, and the @@ -281,7 +315,7 @@ Do not send CLs removing the interior tags from such phrases.

    - Additionally, the go command embeds information about the build + Additionally, the go command embeds information about the build, including build and tool tags (set with -tags), compiler, assembler, and linker flags (like -gcflags), whether cgo was enabled, and if it was, the values of the cgo environment variables @@ -303,6 +337,8 @@ Do not send CLs removing the interior tags from such phrases. debug/buildinfo package from go 1.18+.

    +

    go mod download

    +

    If the main module's go.mod file specifies go 1.17 @@ -316,6 +352,8 @@ Do not send CLs removing the interior tags from such phrases. go mod download all.

    +

    go mod vendor

    +

    The go mod vendor subcommand now supports a -o flag to set the output directory. @@ -325,12 +363,7 @@ Do not send CLs removing the interior tags from such phrases. third-party tools that need to collect package source code.)

    -

    - The go build command and related commands - now support an -asan flag that enables interoperation - with C (or C++) code compiled with the address sanitizer (C compiler - option -fsanitize=address). -

    +

    go mod tidy

    The go mod tidy command now retains @@ -342,6 +375,8 @@ Do not send CLs removing the interior tags from such phrases. module's go.mod file.

    +

    go work

    +

    The go command now supports a "Workspace" mode. If a go.work file is found in the working directory or a @@ -355,6 +390,17 @@ Do not send CLs removing the interior tags from such phrases. documentation.

    +

    go build -asan

    + +

    + The go build command and related commands + now support an -asan flag that enables interoperation + with C (or C++) code compiled with the address sanitizer (C compiler + option -fsanitize=address). +

    + +

    go test

    +

    The go command now supports additional command line options for the new fuzzing support described @@ -376,11 +422,28 @@ Do not send CLs removing the interior tags from such phrases.

    +

    //go:build lines

    +

    - TODO: https://golang.org/cl/240611: 240611: cmd/fix: add buildtag fix +Go 1.17 introduced //go:build lines as a more readable way to write build constraints, +instead of // +build lines. +As of Go 1.17, gofmt adds //go:build lines +to match existing +build lines and keeps them in sync, +while go vet diagnoses when they are out of sync.

    -

    gofmt

    +

    Since the release of Go 1.18 marks the end of support for Go 1.16, +all supported versions of Go now understand //go:build lines. +In Go 1.18, go fix now removes the now-obsolete +// +build lines in modules declaring +go 1.17 or later in their go.mod files. +

    + +

    +For more information, see https://go.dev/design/draft-gobuild. +

    + +

    Gofmt

    gofmt now reads and formats input files concurrently, with a @@ -388,7 +451,7 @@ Do not send CLs removing the interior tags from such phrases. multiple CPUs, gofmt should now be significantly faster.

    -

    vet

    +

    Vet

    Updates for Generics

    @@ -476,7 +539,7 @@ Do not send CLs removing the interior tags from such phrases.

    - The new compiler -asan option supports the + The new -asan compiler option supports the new go command -asan option.

    @@ -506,14 +569,21 @@ Do not send CLs removing the interior tags from such phrases.

    - The new linker -asan option supports the + The new -asan linker option supports the new go command -asan option.

    -

    Build

    +

    Bootstrap

    - TODO: https://golang.org/cl/369914: for default bootstrap, use Go 1.17 if present, falling back to Go 1.4 +When building a Go release from source and GOROOT_BOOTSTRAP +is not set, previous versions of Go looked for a Go 1.4 or later bootstrap toolchain +in the directory $HOME/go1.4 (%HOMEDRIVE%%HOMEPATH%\go1.4 on Windows). +Go now looks first for $HOME/go1.17 or $HOME/sdk/go1.17 +before falling back to $HOME/go1.4. +We intend for Go 1.19 to require Go 1.17 or later for bootstrap, +and this change should make the transition smoother. +For more details, see go.dev/issue/44505.

    Core library

    @@ -640,8 +710,8 @@ Do not send CLs removing the interior tags from such phrases.

    - The methods Reader.Reset and - Writer.Reset + The Reader.Reset and + Writer.Reset methods now use the default buffer size when called on objects with a nil buffer.

    @@ -1003,7 +1073,7 @@ Do not send CLs removing the interior tags from such phrases.
    os/user

    - User.GroupIds. + User.GroupIds now uses a Go native implementation when cgo is not available.

    @@ -1016,7 +1086,7 @@ Do not send CLs removing the interior tags from such phrases. Value.SetIterKey and Value.SetIterValue methods set a Value using a map iterator as the source. They are equivalent to - Value.Set(iter.Key()) and Value.Set(iter.Value()) but + Value.Set(iter.Key()) and Value.Set(iter.Value()), but do fewer allocations.

    @@ -1101,6 +1171,16 @@ Do not send CLs removing the interior tags from such phrases.
    +
    runtime/pprof
    +
    +

    + The CPU profiler now uses per-thread timers on Linux. This increases the + maximum CPU usage that a profile can observe, and reduces some forms of + bias. +

    +
    +
    +
    strconv

    @@ -1170,7 +1250,7 @@ Do not send CLs removing the interior tags from such phrases.

    - SysProcAttr.Pdeathsig. + SysProcAttr.Pdeathsig is now supported in FreeBSD.

    @@ -1179,7 +1259,7 @@ Do not send CLs removing the interior tags from such phrases.
    syscall/js

    - Wrapper interface has been removed. + The Wrapper interface has been removed.

    @@ -1251,7 +1331,7 @@ Do not send CLs removing the interior tags from such phrases.
    unicode/utf8

    - The AppendRune function appends the UTF-8 new + The new AppendRune function appends the UTF-8 encoding of a rune to a []byte.

    diff --git a/doc/go_spec.html b/doc/go_spec.html index bf8b5ed5bf..6c6f982854 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -2008,7 +2008,7 @@ by a value of type T.

    -Additionally, if x's type V or T are type parameters +Additionally, if x's type V or T are type parameters with specific types, x is assignable to a variable of type T if one of the following conditions applies:

    @@ -7414,7 +7414,7 @@ an explicit call to panic or a run-time terminates the execution of F. Any functions deferred by F are then executed as usual. -Next, any deferred functions run by F's caller are run, +Next, any deferred functions run by F's caller are run, and so on up to any deferred by the top-level function in the executing goroutine. At that point, the program is terminated and the error condition is reported, including the value of the argument to panic. diff --git a/misc/cgo/testsanitizers/asan_test.go b/misc/cgo/testsanitizers/asan_test.go index 1b70bce3d1..22dcf23c3b 100644 --- a/misc/cgo/testsanitizers/asan_test.go +++ b/misc/cgo/testsanitizers/asan_test.go @@ -63,7 +63,7 @@ func TestASAN(t *testing.T) { // sanitizer library needs a // symbolizer program and can't find it. const noSymbolizer = "external symbolizer" - // Check if -asan option can correctly print where the error occured. + // Check if -asan option can correctly print where the error occurred. if tc.errorLocation != "" && !strings.Contains(out, tc.errorLocation) && !strings.Contains(out, noSymbolizer) && diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go index c2145bdf91..bc6f7c93bb 100644 --- a/src/cmd/compile/internal/escape/escape.go +++ b/src/cmd/compile/internal/escape/escape.go @@ -10,6 +10,7 @@ import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/logopt" + "cmd/compile/internal/typecheck" "cmd/compile/internal/types" ) @@ -243,6 +244,9 @@ func (b *batch) flowClosure(k hole, clo *ir.ClosureExpr) { n.SetByval(!loc.addrtaken && !loc.reassigned && n.Type().Size() <= 128) if !n.Byval() { n.SetAddrtaken(true) + if n.Sym().Name == typecheck.LocalDictName { + base.FatalfAt(n.Pos(), "dictionary variable not captured by value") + } } if base.Flag.LowerM > 1 { diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 5353435ed1..74e4c0a890 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -217,6 +217,10 @@ func dumpGlobalConst(n ir.Node) { if ir.ConstOverflow(v, t) { return } + } else { + // If the type of the constant is an instantiated generic, we need to emit + // that type so the linker knows about it. See issue 51245. + _ = reflectdata.TypeLinksym(t) } base.Ctxt.DwarfIntConst(base.Ctxt.Pkgpath, n.Sym().Name, types.TypeSymName(t), ir.IntVal(t, v)) } diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index a827987a48..bed4fbb016 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -180,6 +180,14 @@ func ImportData(imports map[string]*types2.Package, data, path string) (pkg *typ p.doDecl(localpkg, name) } + // SetConstraint can't be called if the constraint type is not yet complete. + // When type params are created in the 'P' case of (*importReader).obj(), + // the associated constraint type may not be complete due to recursion. + // Therefore, we defer calling SetConstraint there, and call it here instead + // after all types are complete. + for _, d := range p.later { + d.t.SetConstraint(d.constraint) + } // record all referenced packages as imports list := append(([]*types2.Package)(nil), pkgList[1:]...) sort.Sort(byPath(list)) @@ -191,6 +199,11 @@ func ImportData(imports map[string]*types2.Package, data, path string) (pkg *typ return localpkg, nil } +type setConstraintArgs struct { + t *types2.TypeParam + constraint types2.Type +} + type iimporter struct { exportVersion int64 ipath string @@ -206,6 +219,9 @@ type iimporter struct { tparamIndex map[ident]*types2.TypeParam interfaceList []*types2.Interface + + // Arguments for calls to SetConstraint that are deferred due to recursive types + later []setConstraintArgs } func (p *iimporter) doDecl(pkg *types2.Package, name string) { @@ -401,7 +417,11 @@ func (r *importReader) obj(name string) { } iface.MarkImplicit() } - t.SetConstraint(constraint) + // The constraint type may not be complete, if we + // are in the middle of a type recursion involving type + // constraints. So, we defer SetConstraint until we have + // completely set up all types in ImportData. + r.p.later = append(r.p.later, setConstraintArgs{t: t, constraint: constraint}) case 'V': typ := r.typ() diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index a4e144554c..4b5ae706c1 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -114,7 +114,7 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node { case *syntax.CallExpr: fun := g.expr(expr.Fun) - return Call(pos, g.typ(typ), fun, g.exprs(expr.ArgList), expr.HasDots) + return g.callExpr(pos, g.typ(typ), fun, g.exprs(expr.ArgList), expr.HasDots) case *syntax.IndexExpr: args := unpackListExpr(expr.Index) @@ -206,6 +206,53 @@ func (g *irgen) substType(typ *types.Type, tparams *types.Type, targs []ir.Node) return newt } +// callExpr creates a call expression (which might be a type conversion, built-in +// call, or a regular call) and does standard transforms, unless we are in a generic +// function. +func (g *irgen) callExpr(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) ir.Node { + n := ir.NewCallExpr(pos, ir.OCALL, fun, args) + n.IsDDD = dots + typed(typ, n) + + if fun.Op() == ir.OTYPE { + // Actually a type conversion, not a function call. + if !g.delayTransform() { + return transformConvCall(n) + } + return n + } + + if fun, ok := fun.(*ir.Name); ok && fun.BuiltinOp != 0 { + if !g.delayTransform() { + return transformBuiltin(n) + } + return n + } + + // Add information, now that we know that fun is actually being called. + switch fun := fun.(type) { + case *ir.SelectorExpr: + if fun.Op() == ir.OMETHVALUE { + op := ir.ODOTMETH + if fun.X.Type().IsInterface() { + op = ir.ODOTINTER + } + fun.SetOp(op) + // Set the type to include the receiver, since that's what + // later parts of the compiler expect + fun.SetType(fun.Selection.Type) + } + } + + // A function instantiation (even if fully concrete) shouldn't be + // transformed yet, because we need to add the dictionary during the + // transformation. + if fun.Op() != ir.OFUNCINST && !g.delayTransform() { + transformCall(n) + } + return n +} + // selectorExpr resolves the choice of ODOT, ODOTPTR, OMETHVALUE (eventually // ODOTMETH & ODOTINTER), and OMETHEXPR and deals with embedded fields here rather // than in typecheck.go. diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go index 5524673e66..33acd6051a 100644 --- a/src/cmd/compile/internal/noder/helpers.go +++ b/src/cmd/compile/internal/noder/helpers.go @@ -98,95 +98,6 @@ func Binary(pos src.XPos, op ir.Op, typ *types.Type, x, y ir.Node) *ir.BinaryExp } } -func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) ir.Node { - n := ir.NewCallExpr(pos, ir.OCALL, fun, args) - n.IsDDD = dots - - if fun.Op() == ir.OTYPE { - // Actually a type conversion, not a function call. - if !fun.Type().IsInterface() && - (fun.Type().HasTParam() || args[0].Type().HasTParam()) { - // For type params, we can transform if fun.Type() is known - // to be an interface (in which case a CONVIFACE node will be - // inserted). Otherwise, don't typecheck until we actually - // know the type. - return typed(typ, n) - } - typed(typ, n) - return transformConvCall(n) - } - - if fun, ok := fun.(*ir.Name); ok && fun.BuiltinOp != 0 { - // For most Builtin ops, we delay doing transformBuiltin if any of the - // args have type params, for a variety of reasons: - // - // OMAKE: transformMake can't choose specific ops OMAKESLICE, etc. - // until arg type is known - // OREAL/OIMAG: transformRealImag can't determine type float32/float64 - // until arg type known - // OAPPEND: transformAppend requires that the arg is a slice - // ODELETE: transformDelete requires that the arg is a map - // OALIGNOF, OSIZEOF: can be eval'ed to a constant until types known. - switch fun.BuiltinOp { - case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF: - hasTParam := false - for _, arg := range args { - if fun.BuiltinOp == ir.OOFFSETOF { - // It's the type of left operand of the - // selection that matters, not the type of - // the field itself (which is irrelevant for - // offsetof). - arg = arg.(*ir.SelectorExpr).X - } - if arg.Type().HasTParam() { - hasTParam = true - break - } - } - if hasTParam { - return typed(typ, n) - } - } - - typed(typ, n) - return transformBuiltin(n) - } - - // Add information, now that we know that fun is actually being called. - switch fun := fun.(type) { - case *ir.SelectorExpr: - if fun.Op() == ir.OMETHVALUE { - op := ir.ODOTMETH - if fun.X.Type().IsInterface() { - op = ir.ODOTINTER - } - fun.SetOp(op) - // Set the type to include the receiver, since that's what - // later parts of the compiler expect - fun.SetType(fun.Selection.Type) - } - } - - if fun.Type().HasTParam() || fun.Op() == ir.OXDOT || fun.Op() == ir.OFUNCINST { - // If the fun arg is or has a type param, we can't do all the - // transformations, since we may not have needed properties yet - // (e.g. number of return values, etc). The same applies if a fun - // which is an XDOT could not be transformed yet because of a generic - // type in the X of the selector expression. - // - // A function instantiation (even if fully concrete) shouldn't be - // transformed yet, because we need to add the dictionary during the - // transformation. - return typed(typ, n) - } - - // If no type params, do the normal call transformations. This - // will convert OCALL to OCALLFUNC. - typed(typ, n) - transformCall(n) - return n -} - func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) *ir.BinaryExpr { n := ir.NewBinaryExpr(pos, op, x, y) typed(typ, n) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 50b6c0efcd..9d17d5ffd1 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -410,7 +410,8 @@ func (g *genInst) buildClosure(outer *ir.Func, x ir.Node) ir.Node { fn, formalParams, formalResults := startClosure(pos, outer, typ) // This is the dictionary we want to use. - // It may be a constant, or it may be a dictionary acquired from the outer function's dictionary. + // It may be a constant, it may be the outer functions's dictionary, or it may be + // a subdictionary acquired from the outer function's dictionary. // For the latter, dictVar is a variable in the outer function's scope, set to the subdictionary // read from the outer function's dictionary. var dictVar *ir.Name @@ -640,6 +641,11 @@ func (g *genInst) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMe // over any pointer) recvType := nameNode.Type().Recv().Type recvType = deref(recvType) + if recvType.IsFullyInstantiated() { + // Get the type of the base generic type, so we get + // its original typeparams. + recvType = recvType.OrigSym().Def.(*ir.Name).Type() + } tparams = recvType.RParams() } else { fields := nameNode.Type().TParams().Fields().Slice() @@ -656,11 +662,9 @@ func (g *genInst) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMe s1 := make([]*types.Type, len(shapes)) for i, t := range shapes { var tparam *types.Type - if tparams[i].Kind() == types.TTYPEPARAM { - // Shapes are grouped differently for structural types, so we - // pass the type param to Shapify(), so we can distinguish. - tparam = tparams[i] - } + // Shapes are grouped differently for structural types, so we + // pass the type param to Shapify(), so we can distinguish. + tparam = tparams[i] if !t.IsShape() { s1[i] = typecheck.Shapify(t, i, tparam) } else { @@ -1055,8 +1059,6 @@ func (subst *subster) node(n ir.Node) ir.Node { // Transform the conversion, now that we know the // type argument. m = transformConvCall(call) - // CONVIFACE transformation was already done in noder2 - assert(m.Op() != ir.OCONVIFACE) case ir.OMETHVALUE, ir.OMETHEXPR: // Redo the transformation of OXDOT, now that we @@ -1076,14 +1078,7 @@ func (subst *subster) node(n ir.Node) ir.Node { case ir.ONAME: name := call.X.Name() if name.BuiltinOp != ir.OXXX { - switch name.BuiltinOp { - case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF: - // Transform these builtins now that we - // know the type of the args. - m = transformBuiltin(call) - default: - base.FatalfAt(call.Pos(), "Unexpected builtin op") - } + m = transformBuiltin(call) } else { // This is the case of a function value that was a // type parameter (implied to be a function via a @@ -1154,6 +1149,7 @@ func (subst *subster) node(n ir.Node) ir.Node { newfn.Dcl = append(newfn.Dcl, ldict) as := ir.NewAssignStmt(x.Pos(), ldict, cdict) as.SetTypecheck(1) + ldict.Defn = as newfn.Body.Append(as) // Create inst info for the instantiated closure. The dict diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index bc34d3933a..ef91f550a5 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -354,15 +354,18 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { // declaration before recursing. n := importtype(pos, sym) t := n.Type() + + // Because of recursion, we need to defer width calculations and + // instantiations on intermediate types until the top-level type is + // fully constructed. Note that we can have recursion via type + // constraints. + types.DeferCheckSize() + deferDoInst() if tag == 'U' { rparams := r.typeList() t.SetRParams(rparams) } - // We also need to defer width calculations until - // after the underlying type has been assigned. - types.DeferCheckSize() - deferDoInst() underlying := r.typ() t.SetUnderlying(underlying) diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 9892471142..5147ebbd2c 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -1424,6 +1424,68 @@ func genericTypeName(sym *types.Sym) string { return sym.Name[0:strings.Index(sym.Name, "[")] } +// getShapes appends the list of the shape types that are used within type t to +// listp. The type traversal is simplified for two reasons: (1) we can always stop a +// type traversal when t.HasShape() is false; and (2) shape types can't appear inside +// a named type, except for the type args of a generic type. So, the traversal will +// always stop before we have to deal with recursive types. +func getShapes(t *types.Type, listp *[]*types.Type) { + if !t.HasShape() { + return + } + if t.IsShape() { + *listp = append(*listp, t) + return + } + + if t.Sym() != nil { + // A named type can't have shapes in it, except for type args of a + // generic type. We will have to deal with this differently once we + // alloc local types in generic functions (#47631). + for _, rparam := range t.RParams() { + getShapes(rparam, listp) + } + return + } + + switch t.Kind() { + case types.TARRAY, types.TPTR, types.TSLICE, types.TCHAN: + getShapes(t.Elem(), listp) + + case types.TSTRUCT: + for _, f := range t.FieldSlice() { + getShapes(f.Type, listp) + } + + case types.TFUNC: + for _, f := range t.Recvs().FieldSlice() { + getShapes(f.Type, listp) + } + for _, f := range t.Params().FieldSlice() { + getShapes(f.Type, listp) + } + for _, f := range t.Results().FieldSlice() { + getShapes(f.Type, listp) + } + for _, f := range t.TParams().FieldSlice() { + getShapes(f.Type, listp) + } + + case types.TINTER: + for _, f := range t.Methods().Slice() { + getShapes(f.Type, listp) + } + + case types.TMAP: + getShapes(t.Key(), listp) + getShapes(t.Elem(), listp) + + default: + panic(fmt.Sprintf("Bad type in getShapes: %v", t.Kind())) + } + +} + // Shapify takes a concrete type and a type param index, and returns a GCshape type that can // be used in place of the input type and still generate identical code. // No methods are added - all methods calls directly on a shape should @@ -1432,9 +1494,9 @@ func genericTypeName(sym *types.Sym) string { // For now, we only consider two types to have the same shape, if they have exactly // the same underlying type or they are both pointer types. // -// tparam is the associated typeparam. If there is a structural type for -// the associated type param (not common), then a pointer type t is mapped to its -// underlying type, rather than being merged with other pointers. +// tparam is the associated typeparam - it must be TTYPEPARAM type. If there is a +// structural type for the associated type param (not common), then a pointer type t +// is mapped to its underlying type, rather than being merged with other pointers. // // Shape types are also distinguished by the index of the type in a type param/arg // list. We need to do this so we can distinguish and substitute properly for two @@ -1442,6 +1504,30 @@ func genericTypeName(sym *types.Sym) string { // instantiation. func Shapify(t *types.Type, index int, tparam *types.Type) *types.Type { assert(!t.IsShape()) + if t.HasShape() { + // We are sometimes dealing with types from a shape instantiation + // that were constructed from existing shape types, so t may + // sometimes have shape types inside it. In that case, we find all + // those shape types with getShapes() and replace them with their + // underlying type. + // + // If we don't do this, we may create extra unneeded shape types that + // have these other shape types embedded in them. This may lead to + // generating extra shape instantiations, and a mismatch between the + // instantiations that we used in generating dictionaries and the + // instantations that are actually called. (#51303). + list := []*types.Type{} + getShapes(t, &list) + list2 := make([]*types.Type, len(list)) + for i, shape := range list { + list2[i] = shape.Underlying() + } + ts := Tsubster{ + Tparams: list, + Targs: list2, + } + t = ts.Typ(t) + } // Map all types with the same underlying type to the same shape. u := t.Underlying() diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index e1b395559a..09814ac46d 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -657,7 +657,7 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty // Compute tsym, the symbol that would normally be used as // the field name when embedding f.Type. - // TODO(mdempsky): Check for other occurences of this logic + // TODO(mdempsky): Check for other occurrences of this logic // and deduplicate. typ := f.Type if typ.IsPtr() { diff --git a/src/cmd/compile/internal/types2/assignments.go b/src/cmd/compile/internal/types2/assignments.go index 936930f0b1..d88b03748f 100644 --- a/src/cmd/compile/internal/types2/assignments.go +++ b/src/cmd/compile/internal/types2/assignments.go @@ -294,15 +294,14 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string { return "(" + strings.Join(res, ", ") + ")" } -func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) { - measure := func(x int, unit string) string { - s := fmt.Sprintf("%d %s", x, unit) - if x != 1 { - s += "s" - } - return s +func measure(x int, unit string) string { + if x != 1 { + unit += "s" } + return fmt.Sprintf("%d %s", x, unit) +} +func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) { vars := measure(nvars, "variable") vals := measure(nvals, "value") rhs0 := rhs[0] diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 22f65ed626..d12ee49adb 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -525,7 +525,11 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { } check.exprOrType(x, e.X, false) - if x.mode == invalid { + switch x.mode { + case builtin: + check.errorf(e.Pos(), "cannot select on %s", x) + goto Error + case invalid: goto Error } diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go index 535de0256c..4ec6a7b4fd 100644 --- a/src/cmd/compile/internal/types2/check.go +++ b/src/cmd/compile/internal/types2/check.go @@ -126,7 +126,7 @@ type Checker struct { untyped map[syntax.Expr]exprInfo // map of expressions without final type delayed []action // stack of delayed action segments; segments are processed in FIFO order objPath []Object // path of object dependencies during type inference (for cycle reporting) - defTypes []*Named // defined types created during type checking, for final validation. + cleaners []cleaner // list of types that may need a final cleanup at the end of type-checking // environment within which the current object is type-checked (valid only // for the duration of type-checking a specific object) @@ -205,6 +205,16 @@ func (check *Checker) pop() Object { return obj } +type cleaner interface { + cleanup() +} + +// needsCleanup records objects/types that implement the cleanup method +// which will be called at the end of type-checking. +func (check *Checker) needsCleanup(c cleaner) { + check.cleaners = append(check.cleaners, c) +} + // 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 { @@ -247,6 +257,8 @@ func (check *Checker) initFiles(files []*syntax.File) { check.methods = nil check.untyped = nil check.delayed = nil + check.objPath = nil + check.cleaners = nil // determine package name and collect valid files pkg := check.pkg @@ -315,8 +327,8 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) { print("== processDelayed ==") check.processDelayed(0) // incl. all functions - print("== expandDefTypes ==") - check.expandDefTypes() + print("== cleanup ==") + check.cleanup() print("== initOrder ==") check.initOrder() @@ -344,7 +356,6 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) { check.recvTParamMap = nil check.brokenAliases = nil check.unionTypeSets = nil - check.defTypes = nil check.ctxt = nil // TODO(gri) There's more memory we should release at this point. @@ -372,27 +383,13 @@ func (check *Checker) processDelayed(top int) { check.delayed = check.delayed[:top] } -func (check *Checker) expandDefTypes() { - // Ensure that every defined type created in the course of type-checking has - // either non-*Named underlying, or is unresolved. - // - // This guarantees that we don't leak any types whose underlying is *Named, - // because any unresolved instances will lazily compute their underlying by - // substituting in the underlying of their origin. The origin must have - // either been imported or type-checked and expanded here, and in either case - // its underlying will be fully expanded. - for i := 0; i < len(check.defTypes); i++ { - n := check.defTypes[i] - switch n.underlying.(type) { - case nil: - if n.resolver == nil { - panic("nil underlying") - } - case *Named: - n.under() // n.under may add entries to check.defTypes - } - n.check = nil +// cleanup runs cleanup for all collected cleaners. +func (check *Checker) cleanup() { + // Don't use a range clause since Named.cleanup may add more cleaners. + for i := 0; i < len(check.cleaners); i++ { + check.cleaners[i].cleanup() } + check.cleaners = nil } func (check *Checker) record(x *operand) { diff --git a/src/cmd/compile/internal/types2/conversions.go b/src/cmd/compile/internal/types2/conversions.go index 7fe1d5056b..08b3cbff29 100644 --- a/src/cmd/compile/internal/types2/conversions.go +++ b/src/cmd/compile/internal/types2/conversions.go @@ -49,11 +49,14 @@ func (check *Checker) conversion(x *operand, T Type) { // have specific types, constant x cannot be // converted. ok = T.(*TypeParam).underIs(func(u Type) bool { - // t is nil if there are no specific type terms + // u is nil if there are no specific type terms if u == nil { cause = check.sprintf("%s does not contain specific types", T) return false } + if isString(x.typ) && isBytesOrRunes(u) { + return true + } if !constConvertibleTo(u, nil) { cause = check.sprintf("cannot convert %s to %s (in %s)", x, u, T) return false diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index 0e8f5085ba..579fa55e59 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -569,7 +569,6 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Fiel // Keep track of bounds for later validation. var bound Type - var bounds []Type for i, f := range list { // Optimization: Re-use the previous type bound if it hasn't changed. // This also preserves the grouped output of type parameter lists @@ -584,7 +583,6 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Fiel check.error(f.Type, "cannot use a type parameter as constraint") bound = Typ[Invalid] } - bounds = append(bounds, bound) } tparams[i].bound = bound } diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 02ece21e67..c587c40f80 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -899,7 +899,7 @@ func (check *Checker) incomparableCause(typ Type) string { } // see if we can extract a more specific error var cause string - comparable(typ, nil, func(format string, args ...interface{}) { + comparable(typ, true, nil, func(format string, args ...interface{}) { cause = check.sprintf(format, args...) }) return cause @@ -1360,6 +1360,10 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin // no composite literal type present - use hint (element type of enclosing type) typ = hint base, _ = deref(coreType(typ)) // *T implies &T{} + if base == nil { + check.errorf(e, "invalid composite literal element type %s: no core type", typ) + goto Error + } default: // TODO(gri) provide better error messages depending on context diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go index 1eaddded9a..61009c121e 100644 --- a/src/cmd/compile/internal/types2/index.go +++ b/src/cmd/compile/internal/types2/index.go @@ -182,7 +182,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo } if !valid { - check.errorf(x, invalidOp+"cannot index %s", x) + check.errorf(e.Pos(), invalidOp+"cannot index %s", x) x.mode = invalid return false } diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index 2d6f26c0c9..617f3edad7 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -591,15 +591,24 @@ func (check *Checker) inferB(pos syntax.Pos, tparams []*TypeParam, targs []Type) return } +// adjCoreType returns the core type of tpar unless the +// type parameter embeds a single, possibly named type, +// in which case it returns that single type instead. +// (The core type is always the underlying type of that +// single type.) func adjCoreType(tpar *TypeParam) Type { - // If the type parameter embeds a single, possibly named - // type, use that one instead of the core type (which is - // always the underlying type of that single type). - if single := tpar.singleType(); single != nil { - if debug { - assert(under(single) == coreType(tpar)) + var single *term + if tpar.is(func(t *term) bool { + if single == nil && t != nil { + single = t + return true } - return single + return false // zero or more than one terms + }) { + if debug { + assert(under(single.typ) == coreType(tpar)) + } + return single.typ } return coreType(tpar) } diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index f54938b6e1..c2653a3834 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -204,7 +204,7 @@ func (check *Checker) implements(V, T Type) error { // If T is comparable, V must be comparable. // Remember as a pending error and report only if we don't have a more specific error. var pending error - if Ti.IsComparable() && ((Vi != nil && !Vi.IsComparable()) || (Vi == nil && !Comparable(V))) { + if Ti.IsComparable() && !comparable(V, false, nil, nil) { pending = errorf("%s does not implement comparable", V) } diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index ca5140d092..75597abaf9 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -37,7 +37,7 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { } // set method receivers if necessary - typ := new(Interface) + typ := (*Checker)(nil).newInterface() for _, m := range methods { if sig := m.typ.(*Signature); sig.recv == nil { sig.recv = NewVar(m.pos, m.pkg, "", typ) @@ -54,6 +54,15 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { return typ } +// check may be nil +func (check *Checker) newInterface() *Interface { + typ := &Interface{check: check} + if check != nil { + check.needsCleanup(typ) + } + return typ +} + // MarkImplicit marks the interface t as implicit, meaning this interface // corresponds to a constraint literal such as ~T or A|B without explicit // interface embedding. MarkImplicit should be called before any concurrent use @@ -100,6 +109,11 @@ func (t *Interface) String() string { return TypeString(t, nil) } // ---------------------------------------------------------------------------- // Implementation +func (t *Interface) cleanup() { + t.check = nil + t.embedPos = nil +} + func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType, def *Named) { addEmbedded := func(pos syntax.Pos, typ Type) { ityp.embeddeds = append(ityp.embeddeds, typ) @@ -162,16 +176,10 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType // (don't sort embeddeds: they must correspond to *embedPos entries) sortMethods(ityp.methods) - // Compute type set with a non-nil *Checker as soon as possible - // to report any errors. Subsequent uses of type sets will use - // this computed type set and won't need to pass in a *Checker. - // - // Pin the checker to the interface type in the interim, in case the type set - // must be used before delayed funcs are processed (see issue #48234). - // TODO(rfindley): clean up use of *Checker with computeInterfaceTypeSet - ityp.check = check + // Compute type set as soon as possible to report any errors. + // Subsequent uses of type sets will use this computed type + // set and won't need to pass in a *Checker. check.later(func() { computeInterfaceTypeSet(check, iface.Pos(), ityp) - ityp.check = nil }).describef(iface, "compute type set for %s", ityp) } diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index bb522e8fe3..5c6a1cf5d8 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -72,11 +72,31 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar } // Ensure that typ is always expanded and sanity-checked. if check != nil { - check.defTypes = append(check.defTypes, typ) + check.needsCleanup(typ) } return typ } +func (t *Named) cleanup() { + // Ensure that every defined type created in the course of type-checking has + // either non-*Named underlying, or is unresolved. + // + // This guarantees that we don't leak any types whose underlying is *Named, + // because any unresolved instances will lazily compute their underlying by + // substituting in the underlying of their origin. The origin must have + // either been imported or type-checked and expanded here, and in either case + // its underlying will be fully expanded. + switch t.underlying.(type) { + case nil: + if t.resolver == nil { + panic("nil underlying") + } + case *Named: + t.under() // t.under may add entries to check.cleaners + } + t.check = nil +} + // Obj returns the type name for the declaration defining the named type t. For // instantiated types, this is the type name of the base type. func (t *Named) Obj() *TypeName { return t.orig.obj } // for non-instances this is the same as t.obj @@ -360,11 +380,11 @@ func expandNamed(ctxt *Context, n *Named, instPos syntax.Pos) (tparams *TypePara // that it wasn't substituted. In this case we need to create a new // *Interface before modifying receivers. if iface == n.orig.underlying { - iface = &Interface{ - embeddeds: iface.embeddeds, - complete: iface.complete, - implicit: iface.implicit, // should be false but be conservative - } + old := iface + iface = check.newInterface() + iface.embeddeds = old.embeddeds + iface.complete = old.complete + iface.implicit = old.implicit // should be false but be conservative underlying = iface } iface.methods = methods diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index 0e46333af7..ba259341f6 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -102,11 +102,12 @@ func isGeneric(t Type) bool { // Comparable reports whether values of type T are comparable. func Comparable(T Type) bool { - return comparable(T, nil, nil) + return comparable(T, true, nil, nil) } +// If dynamic is set, non-type parameter interfaces are always comparable. // If reportf != nil, it may be used to report why T is not comparable. -func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})) bool { +func comparable(T Type, dynamic bool, seen map[Type]bool, reportf func(string, ...interface{})) bool { if seen[T] { return true } @@ -124,7 +125,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{}) return true case *Struct: for _, f := range t.fields { - if !comparable(f.typ, seen, nil) { + if !comparable(f.typ, dynamic, seen, nil) { if reportf != nil { reportf("struct containing %s cannot be compared", f.typ) } @@ -133,7 +134,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{}) } return true case *Array: - if !comparable(t.elem, seen, nil) { + if !comparable(t.elem, dynamic, seen, nil) { if reportf != nil { reportf("%s cannot be compared", t) } @@ -141,7 +142,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{}) } return true case *Interface: - return !isTypeParam(T) || t.typeSet().IsComparable(seen) + return dynamic && !isTypeParam(T) || t.typeSet().IsComparable(seen) } return false } diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index c87fab749c..c98024f924 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -116,11 +116,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] // lookup in the scope. for i, p := range rparams { if p.Value == "_" { - tpar := sig.rparams.At(i) if check.recvTParamMap == nil { check.recvTParamMap = make(map[*syntax.Name]*TypeParam) } - check.recvTParamMap[p] = tpar + check.recvTParamMap[p] = tparams[i] } } // determine receiver type to get its type parameters @@ -136,22 +135,23 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] } } // provide type parameter bounds - // - only do this if we have the right number (otherwise an error is reported elsewhere) - if sig.RecvTypeParams().Len() == len(recvTParams) { - // We have a list of *TypeNames but we need a list of Types. - list := make([]Type, sig.RecvTypeParams().Len()) - for i, t := range sig.RecvTypeParams().list() { - list[i] = t - check.mono.recordCanon(t, recvTParams[i]) - } - smap := makeSubstMap(recvTParams, list) - for i, tpar := range sig.RecvTypeParams().list() { - bound := recvTParams[i].bound - // bound is (possibly) parameterized in the context of the - // receiver type declaration. Substitute parameters for the - // current context. - tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil) + if len(tparams) == len(recvTParams) { + smap := makeRenameMap(recvTParams, tparams) + for i, tpar := range tparams { + recvTPar := recvTParams[i] + check.mono.recordCanon(tpar, recvTPar) + // recvTPar.bound is (possibly) parameterized in the context of the + // receiver type declaration. Substitute parameters for the current + // context. + tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil) } + } else if len(tparams) < len(recvTParams) { + // Reporting an error here is a stop-gap measure to avoid crashes in the + // compiler when a type parameter/argument cannot be inferred later. It + // may lead to follow-on errors (see issues #51339, #51343). + // TODO(gri) find a better solution + got := measure(len(tparams), "type parameter") + check.errorf(recvPar, "got %s, but receiver base type declares %d", got, len(recvTParams)) } } } @@ -194,66 +194,69 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] case 1: recv = recvList[0] } + sig.recv = recv - // 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) + // Delay validation of receiver type as it may cause premature expansion + // of types the receiver type is dependent on (see issues #51232, #51233). + check.later(func() { + rtyp, _ := deref(recv.typ) - // 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 rtyp != Typ[Invalid] { - var err string - switch T := rtyp.(type) { - case *Named: - T.resolve(check.bestContext(nil)) - // The receiver type may be an instantiated type referred to - // by an alias (which cannot have receiver parameters for now). - if T.TypeArgs() != nil && sig.RecvTypeParams() == nil { - check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ) - break - } - // 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" + // 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 rtyp != Typ[Invalid] { + var err string + switch T := rtyp.(type) { + case *Named: + T.resolve(check.bestContext(nil)) + // The receiver type may be an instantiated type referred to + // by an alias (which cannot have receiver parameters for now). + if T.TypeArgs() != nil && sig.RecvTypeParams() == nil { + check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ) + break + } + // 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 { + // The underlying type of a receiver base type can be a type parameter; + // e.g. for methods with a generic receiver T[P] with type T[P any] P. + // TODO(gri) Such declarations are currently disallowed. + // Revisit the need for underIs. + underIs(T, func(u Type) bool { + switch u := u.(type) { + case *Basic: + // unsafe.Pointer is treated like a regular pointer + if u.kind == UnsafePointer { + err = "unsafe.Pointer" + return false + } + case *Pointer, *Interface: + err = "pointer or interface type" + return false + } + return true + }) + } + case *Basic: + 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 { - // The underlying type of a receiver base type can be a type parameter; - // e.g. for methods with a generic receiver T[P] with type T[P any] P. - underIs(T, func(u Type) bool { - switch u := u.(type) { - case *Basic: - // unsafe.Pointer is treated like a regular pointer - if u.kind == UnsafePointer { - err = "unsafe.Pointer" - return false - } - case *Pointer, *Interface: - err = "pointer or interface type" - return false - } - return true - }) + default: + check.errorf(recv.pos, "invalid receiver type %s", recv.typ) } - case *Basic: - 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 = "" + if err != "" { + check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err) } - default: - 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 + }).describef(recv, "validate receiver %s", recv) } sig.params = NewTuple(params...) diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index 44a59f55fd..037f04797b 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -160,7 +160,10 @@ func (subst *subster) typ(typ Type) Type { methods, mcopied := subst.funcList(t.methods) embeddeds, ecopied := subst.typeList(t.embeddeds) if mcopied || ecopied { - iface := &Interface{embeddeds: embeddeds, implicit: t.implicit, complete: t.complete} + iface := subst.check.newInterface() + iface.embeddeds = embeddeds + iface.implicit = t.implicit + iface.complete = t.complete // If we've changed the interface type, we may need to replace its // receiver if the receiver type is the original interface. Receivers of // *Named type are replaced during named type expansion. diff --git a/src/cmd/compile/internal/types2/termlist.go b/src/cmd/compile/internal/types2/termlist.go index 844e39e3bf..a0108c4638 100644 --- a/src/cmd/compile/internal/types2/termlist.go +++ b/src/cmd/compile/internal/types2/termlist.go @@ -92,15 +92,6 @@ func (xl termlist) norm() termlist { return rl } -// If the type set represented by xl is specified by a single (non-𝓤) term, -// singleType returns that type. Otherwise it returns nil. -func (xl termlist) singleType() Type { - if nl := xl.norm(); len(nl) == 1 { - return nl[0].typ // if nl.isAll() then typ is nil, which is ok - } - return nil -} - // union returns the union xl ∪ yl. func (xl termlist) union(yl termlist) termlist { return append(xl, yl...).norm() diff --git a/src/cmd/compile/internal/types2/termlist_test.go b/src/cmd/compile/internal/types2/termlist_test.go index 1bdf9e1386..d1e3bdf88e 100644 --- a/src/cmd/compile/internal/types2/termlist_test.go +++ b/src/cmd/compile/internal/types2/termlist_test.go @@ -106,35 +106,6 @@ func TestTermlistNorm(t *testing.T) { } } -func TestTermlistSingleType(t *testing.T) { - // helper to deal with nil types - tstring := func(typ Type) string { - if typ == nil { - return "nil" - } - return typ.String() - } - - for test, want := range map[string]string{ - "∅": "nil", - "𝓤": "nil", - "int": "int", - "myInt": "myInt", - "~int": "int", - "~int ∪ string": "nil", - "~int ∪ myInt": "int", - "∅ ∪ int": "int", - "∅ ∪ ~int": "int", - "∅ ∪ ~int ∪ string": "nil", - } { - xl := maketl(test) - got := tstring(xl.singleType()) - if got != want { - t.Errorf("(%v).singleType() == %v; want %v", test, got, want) - } - } -} - func TestTermlistUnion(t *testing.T) { for _, test := range []struct { xl, yl, want string diff --git a/src/cmd/compile/internal/types2/testdata/examples/methods.go2 b/src/cmd/compile/internal/types2/testdata/examples/methods.go2 index 1d76d553dc..a46f789d60 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/methods.go2 +++ b/src/cmd/compile/internal/types2/testdata/examples/methods.go2 @@ -35,7 +35,7 @@ func (t T1[[ /* ERROR must be an identifier */ ]int]) m2() {} // 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 +// This is no different from locally re-declaring 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. diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go2 new file mode 100644 index 0000000000..6e575a376d --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go2 @@ -0,0 +1,29 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type RC[RG any] interface { + ~[]RG +} + +type Fn[RCT RC[RG], RG any] func(RCT) + +type F[RCT RC[RG], RG any] interface { + Fn() Fn[RCT] +} + +type concreteF[RCT RC[RG], RG any] struct { + makeFn func() Fn[RCT] +} + +func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { + return c.makeFn() +} + +func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] { + return &concreteF[RCT]{ + makeFn: nil, + } +} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51233.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51233.go2 new file mode 100644 index 0000000000..5c8393d039 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51233.go2 @@ -0,0 +1,25 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type RC[RG any] interface { + ~[]RG +} + +type Fn[RCT RC[RG], RG any] func(RCT) + +type FFn[RCT RC[RG], RG any] func() Fn[RCT] + +type F[RCT RC[RG], RG any] interface { + Fn() Fn[RCT] +} + +type concreteF[RCT RC[RG], RG any] struct { + makeFn FFn[RCT] +} + +func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { + return c.makeFn() +} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51257.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51257.go2 new file mode 100644 index 0000000000..bc4208e6ee --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51257.go2 @@ -0,0 +1,46 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func f[_ comparable]() {} + +type S1 struct{ x int } +type S2 struct{ x any } +type S3 struct{ x [10]interface{ m() } } + +func _[P1 comparable, P2 S2]() { + _ = f[S1] + _ = f[S2 /* ERROR S2 does not implement comparable */ ] + _ = f[S3 /* ERROR S3 does not implement comparable */ ] + + type L1 struct { x P1 } + type L2 struct { x P2 } + _ = f[L1] + _ = f[L2 /* ERROR L2 does not implement comparable */ ] +} + + +// example from issue + +type Set[T comparable] map[T]struct{} + +func NewSetFromSlice[T comparable](items []T) *Set[T] { + s := Set[T]{} + + for _, item := range items { + s[item] = struct{}{} + } + + return &s +} + +type T struct{ x any } + +func main() { + NewSetFromSlice( /* ERROR T does not implement comparable */ []T{ + {"foo"}, + {5}, + }) +} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51335.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51335.go2 new file mode 100644 index 0000000000..0b5a1af082 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51335.go2 @@ -0,0 +1,16 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type S1 struct{} +type S2 struct{} + +func _[P *S1|*S2]() { + _= []P{{ /* ERROR invalid composite literal element type P: no core type */ }} +} + +func _[P *S1|S1]() { + _= []P{{ /* ERROR invalid composite literal element type P: no core type */ }} +} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2 new file mode 100644 index 0000000000..40706ec493 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2 @@ -0,0 +1,16 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file is tested when running "go test -run Manual" +// without source arguments. Use for one-off debugging. + +package p + +type T[P any, B *P] struct{} + +func (T /* ERROR cannot use generic type */ ) m0() {} +func (T /* ERROR got 1 type parameter, but receiver base type declares 2 */ [_]) m1() {} +func (T[_, _]) m2() {} +// TODO(gri) this error is unfortunate (issue #51343) +func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51360.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51360.go new file mode 100644 index 0000000000..447ce036ae --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51360.go @@ -0,0 +1,13 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func _() { + len. /* ERROR cannot select on len */ Println + len. /* ERROR cannot select on len */ Println() + _ = len. /* ERROR cannot select on len */ Println + _ = len[ /* ERROR cannot index len */ 0] + _ = *len /* ERROR cannot indirect len */ +} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51386.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51386.go2 new file mode 100644 index 0000000000..ef6223927a --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51386.go2 @@ -0,0 +1,17 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type myString string + +func _[P ~string | ~[]byte | ~[]rune]() { + _ = P("") + const s myString = "" + _ = P(s) +} + +func _[P myString]() { + _ = P("") +} diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index ca8f155791..0fe39dbca4 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -7,9 +7,7 @@ package types2 // 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. + // Underlying returns the underlying type of a type. Underlying() Type // String returns a string representation of a type. diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index 971fdaec73..9ed3369ff4 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -36,6 +36,7 @@ func NewTypeParam(obj *TypeName, constraint Type) *TypeParam { return (*Checker)(nil).newTypeParam(obj, constraint) } +// check may be nil func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam { // Always increment lastID, even if it is not used. id := nextID() @@ -50,9 +51,7 @@ func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam { // iface may mutate typ.bound, so we must ensure that iface() is called // at least once before the resulting TypeParam escapes. if check != nil { - check.later(func() { - typ.iface() - }) + check.needsCleanup(typ) } else if constraint != nil { typ.iface() } @@ -93,9 +92,12 @@ func (t *TypeParam) String() string { return TypeString(t, nil) } // ---------------------------------------------------------------------------- // Implementation +func (t *TypeParam) cleanup() { + t.iface() + t.check = nil +} + // iface returns the constraint interface of t. -// TODO(gri) If we make tparamIsIface the default, this should be renamed to under -// (similar to Named.under). func (t *TypeParam) iface() *Interface { bound := t.bound @@ -136,16 +138,6 @@ func (t *TypeParam) iface() *Interface { return ityp } -// singleType returns the single type of the type parameter constraint; or nil. -func (t *TypeParam) singleType() Type { - return t.iface().typeSet().singleType() -} - -// hasTerms reports whether the type parameter constraint has specific type terms. -func (t *TypeParam) hasTerms() bool { - return t.iface().typeSet().hasTerms() -} - // is calls f with the specific type terms of t's constraint and reports whether // all calls to f returned true. If there are no specific terms, is // returns the result of f(nil). diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index fff348bcf4..65ae04819e 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -39,7 +39,7 @@ func (s *_TypeSet) IsComparable(seen map[Type]bool) bool { return s.comparable } return s.is(func(t *term) bool { - return t != nil && comparable(t.typ, seen, nil) + return t != nil && comparable(t.typ, false, seen, nil) }) } @@ -103,9 +103,6 @@ func (s *_TypeSet) String() string { // hasTerms reports whether the type set has specific type terms. func (s *_TypeSet) hasTerms() bool { return !s.terms.isEmpty() && !s.terms.isAll() } -// singleType returns the single type in s if there is exactly one; otherwise the result is nil. -func (s *_TypeSet) singleType() Type { return s.terms.singleType() } - // subsetOf reports whether s1 ⊆ s2. func (s1 *_TypeSet) subsetOf(s2 *_TypeSet) bool { return s1.terms.subsetOf(s2.terms) } diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 149bd5b0b3..2847aa76c0 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -342,7 +342,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) { return typ case *syntax.InterfaceType: - typ := new(Interface) + typ := check.newInterface() def.setUnderlying(typ) if def != nil { typ.obj = def.obj diff --git a/src/cmd/compile/internal/types2/validtype.go b/src/cmd/compile/internal/types2/validtype.go index c508eadc7c..f365ad1e27 100644 --- a/src/cmd/compile/internal/types2/validtype.go +++ b/src/cmd/compile/internal/types2/validtype.go @@ -79,7 +79,7 @@ func (check *Checker) validType0(typ Type, env *tparamEnv, path []Object) typeIn // would have reported a type cycle and couldn't have been // imported in the first place. assert(t.obj.pkg == check.pkg) - t.underlying = Typ[Invalid] // t is in the current package (no race possibilty) + t.underlying = Typ[Invalid] // t is in the current package (no race possibility) // Find the starting point of the cycle and report it. for i, tn := range path { if tn == t.obj { diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go index 2206c7c840..dfaf16def6 100644 --- a/src/cmd/go/internal/modfetch/coderepo.go +++ b/src/cmd/go/internal/modfetch/coderepo.go @@ -305,17 +305,46 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e // // (If the version is +incompatible, then the go.mod file must not exist: // +incompatible is not an ongoing opt-out from semantic import versioning.) - var canUseIncompatible func() bool - canUseIncompatible = func() bool { - var ok bool - if r.codeDir == "" && r.pathMajor == "" { + incompatibleOk := map[string]bool{} + canUseIncompatible := func(v string) bool { + if r.codeDir != "" || r.pathMajor != "" { + // A non-empty codeDir indicates a module within a subdirectory, + // which necessarily has a go.mod file indicating the module boundary. + // A non-empty pathMajor indicates a module path with a major-version + // suffix, which must match. + return false + } + + ok, seen := incompatibleOk[""] + if !seen { _, errGoMod := r.code.ReadFile(info.Name, "go.mod", codehost.MaxGoMod) - if errGoMod != nil { - ok = true + ok = (errGoMod != nil) + incompatibleOk[""] = ok + } + if !ok { + // A go.mod file exists at the repo root. + return false + } + + // Per https://go.dev/issue/51324, previous versions of the 'go' command + // didn't always check for go.mod files in subdirectories, so if the user + // requests a +incompatible version explicitly, we should continue to allow + // it. Otherwise, if vN/go.mod exists, expect that release tags for that + // major version are intended for the vN module. + if v != "" && !strings.HasSuffix(statVers, "+incompatible") { + major := semver.Major(v) + ok, seen = incompatibleOk[major] + if !seen { + _, errGoModSub := r.code.ReadFile(info.Name, path.Join(major, "go.mod"), codehost.MaxGoMod) + ok = (errGoModSub != nil) + incompatibleOk[major] = ok + } + if !ok { + return false } } - canUseIncompatible = func() bool { return ok } - return ok + + return true } // checkCanonical verifies that the canonical version v is compatible with the @@ -367,7 +396,7 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e base := strings.TrimSuffix(v, "+incompatible") var errIncompatible error if !module.MatchPathMajor(base, r.pathMajor) { - if canUseIncompatible() { + if canUseIncompatible(base) { v = base + "+incompatible" } else { if r.pathMajor != "" { @@ -495,7 +524,7 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e // Save the highest non-retracted canonical tag for the revision. // If we don't find a better match, we'll use it as the canonical version. if tagIsCanonical && semver.Compare(highestCanonical, v) < 0 && !isRetracted(v) { - if module.MatchPathMajor(v, r.pathMajor) || canUseIncompatible() { + if module.MatchPathMajor(v, r.pathMajor) || canUseIncompatible(v) { highestCanonical = v } } @@ -513,12 +542,12 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e // retracted versions. allowedMajor := func(major string) func(v string) bool { return func(v string) bool { - return (major == "" || semver.Major(v) == major) && !isRetracted(v) + return ((major == "" && canUseIncompatible(v)) || semver.Major(v) == major) && !isRetracted(v) } } if pseudoBase == "" { var tag string - if r.pseudoMajor != "" || canUseIncompatible() { + if r.pseudoMajor != "" || canUseIncompatible("") { tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor(r.pseudoMajor)) } else { // Allow either v1 or v0, but not incompatible higher versions. diff --git a/src/cmd/go/internal/modfetch/coderepo_test.go b/src/cmd/go/internal/modfetch/coderepo_test.go index d98ea87da2..bb9268adb8 100644 --- a/src/cmd/go/internal/modfetch/coderepo_test.go +++ b/src/cmd/go/internal/modfetch/coderepo_test.go @@ -458,6 +458,54 @@ var codeRepoTests = []codeRepoTest{ rev: "v3.0.0-devel", err: `resolves to version v0.1.1-0.20220203155313-d59622f6e4d7 (v3.0.0-devel is not a tag)`, }, + + // If v2/go.mod exists, then we should prefer to match the "v2" + // pseudo-versions to the nested module, and resolve the module in the parent + // directory to only compatible versions. + // + // However (https://go.dev/issue/51324), previous versions of the 'go' command + // didn't always do so, so if the user explicitly requests a +incompatible + // version (as would be present in an existing go.mod file), we should + // continue to allow it. + { + vcs: "git", + path: "vcs-test.golang.org/git/v2sub.git", + rev: "80beb17a1603", + version: "v0.0.0-20220222205507-80beb17a1603", + name: "80beb17a16036f17a5aedd1bb5bd6d407b3c6dc5", + short: "80beb17a1603", + time: time.Date(2022, 2, 22, 20, 55, 7, 0, time.UTC), + }, + { + vcs: "git", + path: "vcs-test.golang.org/git/v2sub.git", + rev: "v2.0.0", + err: `module contains a go.mod file, so module path must match major version ("vcs-test.golang.org/git/v2sub.git/v2")`, + }, + { + vcs: "git", + path: "vcs-test.golang.org/git/v2sub.git", + rev: "v2.0.1-0.20220222205507-80beb17a1603", + err: `module contains a go.mod file, so module path must match major version ("vcs-test.golang.org/git/v2sub.git/v2")`, + }, + { + vcs: "git", + path: "vcs-test.golang.org/git/v2sub.git", + rev: "v2.0.0+incompatible", + version: "v2.0.0+incompatible", + name: "5fcd3eaeeb391d399f562fd45a50dac9fc34ae8b", + short: "5fcd3eaeeb39", + time: time.Date(2022, 2, 22, 20, 53, 33, 0, time.UTC), + }, + { + vcs: "git", + path: "vcs-test.golang.org/git/v2sub.git", + rev: "v2.0.1-0.20220222205507-80beb17a1603+incompatible", + version: "v2.0.1-0.20220222205507-80beb17a1603+incompatible", + name: "80beb17a16036f17a5aedd1bb5bd6d407b3c6dc5", + short: "80beb17a1603", + time: time.Date(2022, 2, 22, 20, 55, 7, 0, time.UTC), + }, } func TestCodeRepo(t *testing.T) { diff --git a/src/cmd/go/testdata/script/work.txt b/src/cmd/go/testdata/script/work.txt index a10bf5a1c3..fa1558f9e6 100644 --- a/src/cmd/go/testdata/script/work.txt +++ b/src/cmd/go/testdata/script/work.txt @@ -4,7 +4,7 @@ go env GOWORK ! stdout . go work init ./a ./b -cmp go.work go.work.want +cmpenv go.work go.work.want go env GOWORK stdout '^'$WORK'(\\|/)gopath(\\|/)src(\\|/)go.work$' @@ -69,7 +69,7 @@ use ( ../src/a ) -- go.work.want -- -go 1.18 +go $goversion use ( ./a diff --git a/src/cmd/go/testdata/script/work_edit.txt b/src/cmd/go/testdata/script/work_edit.txt index 71959ca0dd..278afb7f61 100644 --- a/src/cmd/go/testdata/script/work_edit.txt +++ b/src/cmd/go/testdata/script/work_edit.txt @@ -1,10 +1,10 @@ # Test editing go.work files. go work init m -cmp go.work go.work.want_initial +cmpenv go.work go.work.want_initial go work edit -use n -cmp go.work go.work.want_use_n +cmpenv go.work go.work.want_use_n go work edit -go 1.18 cmp go.work go.work.want_go_118 @@ -39,11 +39,11 @@ module m go 1.18 -- go.work.want_initial -- -go 1.18 +go $goversion use ./m -- go.work.want_use_n -- -go 1.18 +go $goversion use ( ./m diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go index 68d9589bf2..843398d3b0 100644 --- a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go +++ b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build riscv64 // +build riscv64 package testbranch diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s index cce296feb5..d7141e38c1 100644 --- a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s +++ b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build riscv64 // +build riscv64 #include "textflag.h" diff --git a/src/crypto/x509/internal/macos/corefoundation.go b/src/crypto/x509/internal/macos/corefoundation.go index cda1d95d81..75c212910b 100644 --- a/src/crypto/x509/internal/macos/corefoundation.go +++ b/src/crypto/x509/internal/macos/corefoundation.go @@ -48,7 +48,7 @@ func CFStringToString(ref CFRef) string { // TimeToCFDateRef converts a time.Time into an apple CFDateRef func TimeToCFDateRef(t time.Time) CFRef { secs := t.Sub(time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)).Seconds() - ref := CFDateCreate(int(secs)) + ref := CFDateCreate(secs) return ref } @@ -170,8 +170,8 @@ func x509_CFArrayAppendValue_trampoline() //go:cgo_import_dynamic x509_CFDateCreate CFDateCreate "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation" -func CFDateCreate(seconds int) CFRef { - ret := syscall(abi.FuncPCABI0(x509_CFDateCreate_trampoline), kCFAllocatorDefault, uintptr(seconds), 0, 0, 0, 0) +func CFDateCreate(seconds float64) CFRef { + ret := syscall(abi.FuncPCABI0(x509_CFDateCreate_trampoline), kCFAllocatorDefault, 0, 0, 0, 0, seconds) return CFRef(ret) } func x509_CFDateCreate_trampoline() @@ -193,7 +193,7 @@ func CFStringCreateExternalRepresentation(strRef CFRef) CFRef { func x509_CFStringCreateExternalRepresentation_trampoline() // syscall is implemented in the runtime package (runtime/sys_darwin.go) -func syscall(fn, a1, a2, a3, a4, a5, a6 uintptr) uintptr +func syscall(fn, a1, a2, a3, a4, a5 uintptr, f1 float64) uintptr // ReleaseCFArray iterates through an array, releasing its contents, and then // releases the array itself. This is necessary because we cannot, easily, set the diff --git a/src/encoding/xml/marshal.go b/src/encoding/xml/marshal.go index 6859be04a2..7792ac77f8 100644 --- a/src/encoding/xml/marshal.go +++ b/src/encoding/xml/marshal.go @@ -512,7 +512,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat } fv := finfo.value(val, dontInitNilPointers) - if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) { + if finfo.flags&fOmitEmpty != 0 && (!fv.IsValid() || isEmptyValue(fv)) { continue } diff --git a/src/encoding/xml/marshal_test.go b/src/encoding/xml/marshal_test.go index 5fdbae7ef0..3fe7e2dc00 100644 --- a/src/encoding/xml/marshal_test.go +++ b/src/encoding/xml/marshal_test.go @@ -2495,3 +2495,39 @@ func TestInvalidXMLName(t *testing.T) { t.Errorf("error %q does not contain %q", err, want) } } + +// Issue 50164. Crash on zero value XML attribute. +type LayerOne struct { + XMLName Name `xml:"l1"` + + Value *float64 `xml:"value,omitempty"` + *LayerTwo `xml:",omitempty"` +} + +type LayerTwo struct { + ValueTwo *int `xml:"value_two,attr,omitempty"` +} + +func TestMarshalZeroValue(t *testing.T) { + proofXml := `1.2345` + var l1 LayerOne + err := Unmarshal([]byte(proofXml), &l1) + if err != nil { + t.Fatalf("unmarshal XML error: %v", err) + } + want := float64(1.2345) + got := *l1.Value + if got != want { + t.Fatalf("unexpected unmarshal result, want %f but got %f", want, got) + } + + // Marshal again (or Encode again) + // In issue 50164, here `Marshal(l1)` will panic because of the zero value of xml attribute ValueTwo `value_two`. + anotherXML, err := Marshal(l1) + if err != nil { + t.Fatalf("marshal XML error: %v", err) + } + if string(anotherXML) != proofXml { + t.Fatalf("unexpected unmarshal result, want %q but got %q", proofXml, anotherXML) + } +} diff --git a/src/go/internal/gcimporter/iimport.go b/src/go/internal/gcimporter/iimport.go index 8ec4c5413b..bff1c09cc9 100644 --- a/src/go/internal/gcimporter/iimport.go +++ b/src/go/internal/gcimporter/iimport.go @@ -181,6 +181,15 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, dataRea p.doDecl(localpkg, name) } + // SetConstraint can't be called if the constraint type is not yet complete. + // When type params are created in the 'P' case of (*importReader).obj(), + // the associated constraint type may not be complete due to recursion. + // Therefore, we defer calling SetConstraint there, and call it here instead + // after all types are complete. + for _, d := range p.later { + d.t.SetConstraint(d.constraint) + } + for _, typ := range p.interfaceList { typ.Complete() } @@ -195,6 +204,11 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, dataRea return localpkg, nil } +type setConstraintArgs struct { + t *types.TypeParam + constraint types.Type +} + type iimporter struct { exportVersion int64 ipath string @@ -211,6 +225,9 @@ type iimporter struct { fake fakeFileSet interfaceList []*types.Interface + + // Arguments for calls to SetConstraint that are deferred due to recursive types + later []setConstraintArgs } func (p *iimporter) doDecl(pkg *types.Package, name string) { @@ -391,7 +408,11 @@ func (r *importReader) obj(name string) { } iface.MarkImplicit() } - t.SetConstraint(constraint) + // The constraint type may not be complete, if we + // are in the middle of a type recursion involving type + // constraints. So, we defer SetConstraint until we have + // completely set up all types in ImportData. + r.p.later = append(r.p.later, setConstraintArgs{t: t, constraint: constraint}) case 'V': typ := r.typ() diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go index f75b8b6f6b..f5e22c2f67 100644 --- a/src/go/types/assignments.go +++ b/src/go/types/assignments.go @@ -290,15 +290,14 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string { return "(" + strings.Join(res, ", ") + ")" } -func (check *Checker) assignError(rhs []ast.Expr, nvars, nvals int) { - measure := func(x int, unit string) string { - s := fmt.Sprintf("%d %s", x, unit) - if x != 1 { - s += "s" - } - return s +func measure(x int, unit string) string { + if x != 1 { + unit += "s" } + return fmt.Sprintf("%d %s", x, unit) +} +func (check *Checker) assignError(rhs []ast.Expr, nvars, nvals int) { vars := measure(nvars, "variable") vals := measure(nvals, "value") rhs0 := rhs[0] diff --git a/src/go/types/call.go b/src/go/types/call.go index 3dab284459..854528ddfa 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -527,7 +527,12 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { } check.exprOrType(x, e.X, false) - if x.mode == invalid { + switch x.mode { + case builtin: + // types2 uses the position of '.' for the error + check.errorf(e.Sel, _UncalledBuiltin, "cannot select on %s", x) + goto Error + case invalid: goto Error } diff --git a/src/go/types/check.go b/src/go/types/check.go index 6e1da04b9f..23136377c8 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -133,7 +133,7 @@ type Checker struct { untyped map[ast.Expr]exprInfo // map of expressions without final type delayed []action // stack of delayed action segments; segments are processed in FIFO order objPath []Object // path of object dependencies during type inference (for cycle reporting) - defTypes []*Named // defined types created during type checking, for final validation. + cleaners []cleaner // list of types that may need a final cleanup at the end of type-checking // environment within which the current object is type-checked (valid only // for the duration of type-checking a specific object) @@ -212,6 +212,16 @@ func (check *Checker) pop() Object { return obj } +type cleaner interface { + cleanup() +} + +// needsCleanup records objects/types that implement the cleanup method +// which will be called at the end of type-checking. +func (check *Checker) needsCleanup(c cleaner) { + check.cleaners = append(check.cleaners, c) +} + // NewChecker returns a new Checker instance for a given package. // Package files may be added incrementally via checker.Files. func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker { @@ -255,6 +265,8 @@ func (check *Checker) initFiles(files []*ast.File) { check.methods = nil check.untyped = nil check.delayed = nil + check.objPath = nil + check.cleaners = nil // determine package name and collect valid files pkg := check.pkg @@ -304,22 +316,37 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) { defer check.handleBailout(&err) + print := func(msg string) { + if trace { + fmt.Println() + 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.expandDefTypes() + print("== cleanup ==") + check.cleanup() + print("== initOrder ==") check.initOrder() if !check.conf.DisableUnusedImportCheck { + print("== unusedImports ==") check.unusedImports() } + print("== recordUntyped ==") check.recordUntyped() if check.firstErr == nil { @@ -337,7 +364,6 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) { check.recvTParamMap = nil check.brokenAliases = nil check.unionTypeSets = nil - check.defTypes = nil check.ctxt = nil // TODO(rFindley) There's more memory we should release at this point. @@ -365,27 +391,13 @@ func (check *Checker) processDelayed(top int) { check.delayed = check.delayed[:top] } -func (check *Checker) expandDefTypes() { - // Ensure that every defined type created in the course of type-checking has - // either non-*Named underlying, or is unresolved. - // - // This guarantees that we don't leak any types whose underlying is *Named, - // because any unresolved instances will lazily compute their underlying by - // substituting in the underlying of their origin. The origin must have - // either been imported or type-checked and expanded here, and in either case - // its underlying will be fully expanded. - for i := 0; i < len(check.defTypes); i++ { - n := check.defTypes[i] - switch n.underlying.(type) { - case nil: - if n.resolver == nil { - panic("nil underlying") - } - case *Named: - n.under() // n.under may add entries to check.defTypes - } - n.check = nil +// cleanup runs cleanup for all collected cleaners. +func (check *Checker) cleanup() { + // Don't use a range clause since Named.cleanup may add more cleaners. + for i := 0; i < len(check.cleaners); i++ { + check.cleaners[i].cleanup() } + check.cleaners = nil } func (check *Checker) record(x *operand) { diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go index 84741359c0..c5a69cddf4 100644 --- a/src/go/types/conversions.go +++ b/src/go/types/conversions.go @@ -48,11 +48,14 @@ func (check *Checker) conversion(x *operand, T Type) { // have specific types, constant x cannot be // converted. ok = T.(*TypeParam).underIs(func(u Type) bool { - // t is nil if there are no specific type terms + // u is nil if there are no specific type terms if u == nil { cause = check.sprintf("%s does not contain specific types", T) return false } + if isString(x.typ) && isBytesOrRunes(u) { + return true + } if !constConvertibleTo(u, nil) { cause = check.sprintf("cannot convert %s to %s (in %s)", x, u, T) return false diff --git a/src/go/types/decl.go b/src/go/types/decl.go index cd6f709a56..93a37d76ce 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -624,7 +624,6 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list *ast.FieldList }() index := 0 - var bounds []Type for _, f := range list.List { var bound Type // NOTE: we may be able to assert that f.Type != nil here, but this is not @@ -642,7 +641,6 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list *ast.FieldList } else { bound = Typ[Invalid] } - bounds = append(bounds, bound) for i := range f.Names { tparams[index+i].bound = bound } diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 8747838c4b..9241c243f2 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -859,7 +859,7 @@ func (check *Checker) incomparableCause(typ Type) string { } // see if we can extract a more specific error var cause string - comparable(typ, nil, func(format string, args ...interface{}) { + comparable(typ, true, nil, func(format string, args ...interface{}) { cause = check.sprintf(format, args...) }) return cause @@ -1339,6 +1339,10 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { // no composite literal type present - use hint (element type of enclosing type) typ = hint base, _ = deref(coreType(typ)) // *T implies &T{} + if base == nil { + check.errorf(e, _InvalidLit, "invalid composite literal element type %s: no core type", typ) + goto Error + } default: // TODO(gri) provide better error messages depending on context diff --git a/src/go/types/index.go b/src/go/types/index.go index eac6017ba2..33075edaf1 100644 --- a/src/go/types/index.go +++ b/src/go/types/index.go @@ -183,6 +183,7 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst } if !valid { + // types2 uses the position of '[' for the error check.invalidOp(x, _NonIndexableOperand, "cannot index %s", x) x.mode = invalid return false diff --git a/src/go/types/infer.go b/src/go/types/infer.go index 8f22144c83..d481aaa877 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -590,15 +590,24 @@ func (check *Checker) inferB(posn positioner, tparams []*TypeParam, targs []Type return } +// adjCoreType returns the core type of tpar unless the +// type parameter embeds a single, possibly named type, +// in which case it returns that single type instead. +// (The core type is always the underlying type of that +// single type.) func adjCoreType(tpar *TypeParam) Type { - // If the type parameter embeds a single, possibly named - // type, use that one instead of the core type (which is - // always the underlying type of that single type). - if single := tpar.singleType(); single != nil { - if debug { - assert(under(single) == coreType(tpar)) + var single *term + if tpar.is(func(t *term) bool { + if single == nil && t != nil { + single = t + return true } - return single + return false // zero or more than one terms + }) { + if debug { + assert(under(single.typ) == coreType(tpar)) + } + return single.typ } return coreType(tpar) } diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 4aeaeb7f11..4b8e3d4661 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -204,7 +204,7 @@ func (check *Checker) implements(V, T Type) error { // If T is comparable, V must be comparable. // Remember as a pending error and report only if we don't have a more specific error. var pending error - if Ti.IsComparable() && ((Vi != nil && !Vi.IsComparable()) || (Vi == nil && !Comparable(V))) { + if Ti.IsComparable() && !comparable(V, false, nil, nil) { pending = errorf("%s does not implement comparable", V) } diff --git a/src/go/types/interface.go b/src/go/types/interface.go index b9d4660eb4..3db3580a91 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -56,7 +56,7 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { } // set method receivers if necessary - typ := new(Interface) + typ := (*Checker)(nil).newInterface() for _, m := range methods { if sig := m.typ.(*Signature); sig.recv == nil { sig.recv = NewVar(m.pos, m.pkg, "", typ) @@ -73,6 +73,15 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface { return typ } +// check may be nil +func (check *Checker) newInterface() *Interface { + typ := &Interface{check: check} + if check != nil { + check.needsCleanup(typ) + } + return typ +} + // MarkImplicit marks the interface t as implicit, meaning this interface // corresponds to a constraint literal such as ~T or A|B without explicit // interface embedding. MarkImplicit should be called before any concurrent use @@ -141,6 +150,11 @@ func (t *Interface) String() string { return TypeString(t, nil) } // ---------------------------------------------------------------------------- // Implementation +func (t *Interface) cleanup() { + t.check = nil + t.embedPos = nil +} + func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) { addEmbedded := func(pos token.Pos, typ Type) { ityp.embeddeds = append(ityp.embeddeds, typ) @@ -210,16 +224,10 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d sortMethods(ityp.methods) // (don't sort embeddeds: they must correspond to *embedPos entries) - // Compute type set with a non-nil *Checker as soon as possible - // to report any errors. Subsequent uses of type sets will use - // this computed type set and won't need to pass in a *Checker. - // - // Pin the checker to the interface type in the interim, in case the type set - // must be used before delayed funcs are processed (see issue #48234). - // TODO(rfindley): clean up use of *Checker with computeInterfaceTypeSet - ityp.check = check + // Compute type set as soon as possible to report any errors. + // Subsequent uses of type sets will use this computed type + // set and won't need to pass in a *Checker. check.later(func() { computeInterfaceTypeSet(check, iface.Pos(), ityp) - ityp.check = nil }).describef(iface, "compute type set for %s", ityp) } diff --git a/src/go/types/named.go b/src/go/types/named.go index 5e84c39776..5b84e0653b 100644 --- a/src/go/types/named.go +++ b/src/go/types/named.go @@ -72,11 +72,31 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar } // Ensure that typ is always expanded and sanity-checked. if check != nil { - check.defTypes = append(check.defTypes, typ) + check.needsCleanup(typ) } return typ } +func (t *Named) cleanup() { + // Ensure that every defined type created in the course of type-checking has + // either non-*Named underlying, or is unresolved. + // + // This guarantees that we don't leak any types whose underlying is *Named, + // because any unresolved instances will lazily compute their underlying by + // substituting in the underlying of their origin. The origin must have + // either been imported or type-checked and expanded here, and in either case + // its underlying will be fully expanded. + switch t.underlying.(type) { + case nil: + if t.resolver == nil { + panic("nil underlying") + } + case *Named: + t.under() // t.under may add entries to check.cleaners + } + t.check = nil +} + // Obj returns the type name for the declaration defining the named type t. For // instantiated types, this is the type name of the base type. func (t *Named) Obj() *TypeName { @@ -362,11 +382,11 @@ func expandNamed(ctxt *Context, n *Named, instPos token.Pos) (tparams *TypeParam // that it wasn't substituted. In this case we need to create a new // *Interface before modifying receivers. if iface == n.orig.underlying { - iface = &Interface{ - embeddeds: iface.embeddeds, - complete: iface.complete, - implicit: iface.implicit, // should be false but be conservative - } + old := iface + iface = check.newInterface() + iface.embeddeds = old.embeddeds + iface.complete = old.complete + iface.implicit = old.implicit // should be false but be conservative underlying = iface } iface.methods = methods diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 14e99bf426..0360f27ee6 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -104,11 +104,12 @@ func isGeneric(t Type) bool { // Comparable reports whether values of type T are comparable. func Comparable(T Type) bool { - return comparable(T, nil, nil) + return comparable(T, true, nil, nil) } +// If dynamic is set, non-type parameter interfaces are always comparable. // If reportf != nil, it may be used to report why T is not comparable. -func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})) bool { +func comparable(T Type, dynamic bool, seen map[Type]bool, reportf func(string, ...interface{})) bool { if seen[T] { return true } @@ -126,7 +127,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{}) return true case *Struct: for _, f := range t.fields { - if !comparable(f.typ, seen, nil) { + if !comparable(f.typ, dynamic, seen, nil) { if reportf != nil { reportf("struct containing %s cannot be compared", f.typ) } @@ -135,7 +136,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{}) } return true case *Array: - if !comparable(t.elem, seen, nil) { + if !comparable(t.elem, dynamic, seen, nil) { if reportf != nil { reportf("%s cannot be compared", t) } @@ -143,7 +144,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{}) } return true case *Interface: - return !isTypeParam(T) || t.typeSet().IsComparable(seen) + return dynamic && !isTypeParam(T) || t.typeSet().IsComparable(seen) } return false } diff --git a/src/go/types/signature.go b/src/go/types/signature.go index 8f89e931fb..a340ac701e 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -112,7 +112,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast // - the receiver specification acts as local declaration for its type parameters, which may be blank _, rname, rparams := check.unpackRecv(recvPar.List[0].Type, true) if len(rparams) > 0 { - sig.rparams = bindTParams(check.declareTypeParams(nil, rparams)) + tparams := check.declareTypeParams(nil, rparams) + sig.rparams = bindTParams(tparams) // Blank identifiers don't get declared, so naive type-checking of the // receiver type expression would fail in Checker.collectParams below, // when Checker.ident cannot resolve the _ to a type. @@ -122,11 +123,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast // lookup in the scope. for i, p := range rparams { if p.Name == "_" { - tpar := sig.rparams.At(i) if check.recvTParamMap == nil { check.recvTParamMap = make(map[*ast.Ident]*TypeParam) } - check.recvTParamMap[p] = tpar + check.recvTParamMap[p] = tparams[i] } } // determine receiver type to get its type parameters @@ -142,22 +142,23 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast } } // provide type parameter bounds - // - only do this if we have the right number (otherwise an error is reported elsewhere) - if sig.RecvTypeParams().Len() == len(recvTParams) { - // We have a list of *TypeNames but we need a list of Types. - list := make([]Type, sig.RecvTypeParams().Len()) - for i, t := range sig.RecvTypeParams().list() { - list[i] = t - check.mono.recordCanon(t, recvTParams[i]) - } - smap := makeSubstMap(recvTParams, list) - for i, tpar := range sig.RecvTypeParams().list() { - bound := recvTParams[i].bound - // bound is (possibly) parameterized in the context of the - // receiver type declaration. Substitute parameters for the - // current context. - tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil) + if len(tparams) == len(recvTParams) { + smap := makeRenameMap(recvTParams, tparams) + for i, tpar := range tparams { + recvTPar := recvTParams[i] + check.mono.recordCanon(tpar, recvTPar) + // recvTPar.bound is (possibly) parameterized in the context of the + // receiver type declaration. Substitute parameters for the current + // context. + tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil) } + } else if len(tparams) < len(recvTParams) { + // Reporting an error here is a stop-gap measure to avoid crashes in the + // compiler when a type parameter/argument cannot be inferred later. It + // may lead to follow-on errors (see issues #51339, #51343). + // TODO(gri) find a better solution + got := measure(len(tparams), "type parameter") + check.errorf(recvPar, _BadRecv, "got %s, but receiver base type declares %d", got, len(recvTParams)) } } } @@ -192,66 +193,77 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast switch len(recvList) { case 0: // error reported by resolver - recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below + recv = NewParam(token.NoPos, nil, "", Typ[Invalid]) // ignore recv below default: // more than one receiver - check.error(recvList[len(recvList)-1], _BadRecv, "method must have exactly one receiver") + check.error(recvList[len(recvList)-1], _InvalidRecv, "method must have exactly one receiver") fallthrough // continue with first receiver case 1: recv = recvList[0] } + sig.recv = recv - // 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) + // Delay validation of receiver type as it may cause premature expansion + // of types the receiver type is dependent on (see issues #51232, #51233). + check.later(func() { + rtyp, _ := deref(recv.typ) - // 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 rtyp != Typ[Invalid] { - var err string - switch T := rtyp.(type) { - case *Named: - T.resolve(check.bestContext(nil)) - // The receiver type may be an instantiated type referred to - // by an alias (which cannot have receiver parameters for now). - if T.TypeArgs() != nil && sig.RecvTypeParams() == nil { - check.errorf(atPos(recv.pos), _InvalidRecv, "cannot define methods on instantiated type %s", recv.typ) - break - } - // 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" - } else { - // The underlying type of a receiver base type can be a type parameter; - // e.g. for methods with a generic receiver T[P] with type T[P any] P. - underIs(T, func(u Type) bool { - switch u := u.(type) { - case *Basic: - // unsafe.Pointer is treated like a regular pointer - if u.kind == UnsafePointer { - err = "unsafe.Pointer" + // 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 rtyp != Typ[Invalid] { + var err string + switch T := rtyp.(type) { + case *Named: + T.resolve(check.bestContext(nil)) + // The receiver type may be an instantiated type referred to + // by an alias (which cannot have receiver parameters for now). + if T.TypeArgs() != nil && sig.RecvTypeParams() == nil { + check.errorf(recv, _InvalidRecv, "cannot define methods on instantiated type %s", recv.typ) + break + } + // 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 compilerErrorMessages { + check.errorf(recv, _InvalidRecv, "cannot define new methods on non-local type %s", recv.typ) + err = "" + } + } else { + // The underlying type of a receiver base type can be a type parameter; + // e.g. for methods with a generic receiver T[P] with type T[P any] P. + // TODO(gri) Such declarations are currently disallowed. + // Revisit the need for underIs. + underIs(T, func(u Type) bool { + switch u := u.(type) { + case *Basic: + // unsafe.Pointer is treated like a regular pointer + if u.kind == UnsafePointer { + err = "unsafe.Pointer" + return false + } + case *Pointer, *Interface: + err = "pointer or interface type" return false } - case *Pointer, *Interface: - err = "pointer or interface type" - return false - } - return true - }) + return true + }) + } + case *Basic: + err = "basic or unnamed type" + if compilerErrorMessages { + check.errorf(recv, _InvalidRecv, "cannot define new methods on non-local type %s", recv.typ) + err = "" + } + default: + check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ) + } + if err != "" { + check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err) } - case *Basic: - err = "basic or unnamed type" - default: - check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ) } - if err != "" { - check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err) - // ok to continue - } - } - sig.recv = recv + }).describef(recv, "validate receiver %s", recv) } sig.params = NewTuple(params...) diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 53247a3585..4b4a0f4ad6 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -160,7 +160,10 @@ func (subst *subster) typ(typ Type) Type { methods, mcopied := subst.funcList(t.methods) embeddeds, ecopied := subst.typeList(t.embeddeds) if mcopied || ecopied { - iface := &Interface{embeddeds: embeddeds, implicit: t.implicit, complete: t.complete} + iface := subst.check.newInterface() + iface.embeddeds = embeddeds + iface.implicit = t.implicit + iface.complete = t.complete // If we've changed the interface type, we may need to replace its // receiver if the receiver type is the original interface. Receivers of // *Named type are replaced during named type expansion. diff --git a/src/go/types/termlist.go b/src/go/types/termlist.go index c4ab0e037e..94e49caee0 100644 --- a/src/go/types/termlist.go +++ b/src/go/types/termlist.go @@ -92,15 +92,6 @@ func (xl termlist) norm() termlist { return rl } -// If the type set represented by xl is specified by a single (non-𝓤) term, -// singleType returns that type. Otherwise it returns nil. -func (xl termlist) singleType() Type { - if nl := xl.norm(); len(nl) == 1 { - return nl[0].typ // if nl.isAll() then typ is nil, which is ok - } - return nil -} - // union returns the union xl ∪ yl. func (xl termlist) union(yl termlist) termlist { return append(xl, yl...).norm() diff --git a/src/go/types/termlist_test.go b/src/go/types/termlist_test.go index dddca7a682..f0d58ac1bc 100644 --- a/src/go/types/termlist_test.go +++ b/src/go/types/termlist_test.go @@ -106,35 +106,6 @@ func TestTermlistNorm(t *testing.T) { } } -func TestTermlistSingleType(t *testing.T) { - // helper to deal with nil types - tstring := func(typ Type) string { - if typ == nil { - return "nil" - } - return typ.String() - } - - for test, want := range map[string]string{ - "∅": "nil", - "𝓤": "nil", - "int": "int", - "myInt": "myInt", - "~int": "int", - "~int ∪ string": "nil", - "~int ∪ myInt": "int", - "∅ ∪ int": "int", - "∅ ∪ ~int": "int", - "∅ ∪ ~int ∪ string": "nil", - } { - xl := maketl(test) - got := tstring(xl.singleType()) - if got != want { - t.Errorf("(%v).singleType() == %v; want %v", test, got, want) - } - } -} - func TestTermlistUnion(t *testing.T) { for _, test := range []struct { xl, yl, want string diff --git a/src/go/types/testdata/examples/methods.go2 b/src/go/types/testdata/examples/methods.go2 index 1d76d553dc..a46f789d60 100644 --- a/src/go/types/testdata/examples/methods.go2 +++ b/src/go/types/testdata/examples/methods.go2 @@ -35,7 +35,7 @@ func (t T1[[ /* ERROR must be an identifier */ ]int]) m2() {} // 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 +// This is no different from locally re-declaring 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. diff --git a/src/go/types/testdata/fixedbugs/issue51232.go2 b/src/go/types/testdata/fixedbugs/issue51232.go2 new file mode 100644 index 0000000000..6e575a376d --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue51232.go2 @@ -0,0 +1,29 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type RC[RG any] interface { + ~[]RG +} + +type Fn[RCT RC[RG], RG any] func(RCT) + +type F[RCT RC[RG], RG any] interface { + Fn() Fn[RCT] +} + +type concreteF[RCT RC[RG], RG any] struct { + makeFn func() Fn[RCT] +} + +func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { + return c.makeFn() +} + +func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] { + return &concreteF[RCT]{ + makeFn: nil, + } +} diff --git a/src/go/types/testdata/fixedbugs/issue51233.go2 b/src/go/types/testdata/fixedbugs/issue51233.go2 new file mode 100644 index 0000000000..5c8393d039 --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue51233.go2 @@ -0,0 +1,25 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type RC[RG any] interface { + ~[]RG +} + +type Fn[RCT RC[RG], RG any] func(RCT) + +type FFn[RCT RC[RG], RG any] func() Fn[RCT] + +type F[RCT RC[RG], RG any] interface { + Fn() Fn[RCT] +} + +type concreteF[RCT RC[RG], RG any] struct { + makeFn FFn[RCT] +} + +func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { + return c.makeFn() +} diff --git a/src/go/types/testdata/fixedbugs/issue51257.go2 b/src/go/types/testdata/fixedbugs/issue51257.go2 new file mode 100644 index 0000000000..8a3eb3278d --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue51257.go2 @@ -0,0 +1,46 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func f[_ comparable]() {} + +type S1 struct{ x int } +type S2 struct{ x any } +type S3 struct{ x [10]interface{ m() } } + +func _[P1 comparable, P2 S2]() { + _ = f[S1] + _ = f[S2 /* ERROR S2 does not implement comparable */ ] + _ = f[S3 /* ERROR S3 does not implement comparable */ ] + + type L1 struct { x P1 } + type L2 struct { x P2 } + _ = f[L1] + _ = f[L2 /* ERROR L2 does not implement comparable */ ] +} + + +// example from issue + +type Set[T comparable] map[T]struct{} + +func NewSetFromSlice[T comparable](items []T) *Set[T] { + s := Set[T]{} + + for _, item := range items { + s[item] = struct{}{} + } + + return &s +} + +type T struct{ x any } + +func main() { + NewSetFromSlice /* ERROR T does not implement comparable */ ([]T{ + {"foo"}, + {5}, + }) +} diff --git a/src/go/types/testdata/fixedbugs/issue51335.go2 b/src/go/types/testdata/fixedbugs/issue51335.go2 new file mode 100644 index 0000000000..0b5a1af082 --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue51335.go2 @@ -0,0 +1,16 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type S1 struct{} +type S2 struct{} + +func _[P *S1|*S2]() { + _= []P{{ /* ERROR invalid composite literal element type P: no core type */ }} +} + +func _[P *S1|S1]() { + _= []P{{ /* ERROR invalid composite literal element type P: no core type */ }} +} diff --git a/src/go/types/testdata/fixedbugs/issue51339.go2 b/src/go/types/testdata/fixedbugs/issue51339.go2 new file mode 100644 index 0000000000..6803c44d76 --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue51339.go2 @@ -0,0 +1,16 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file is tested when running "go test -run Manual" +// without source arguments. Use for one-off debugging. + +package p + +type T[P any, B *P] struct{} + +func (T /* ERROR cannot use generic type */ ) m0() {} +func (/* ERROR got 1 type parameter, but receiver base type declares 2 */ T[_]) m1() {} +func (T[_, _]) m2() {} +// TODO(gri) this error is unfortunate (issue #51343) +func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {} diff --git a/src/go/types/testdata/fixedbugs/issue51360.go b/src/go/types/testdata/fixedbugs/issue51360.go new file mode 100644 index 0000000000..fe3de04dbf --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue51360.go @@ -0,0 +1,13 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func _() { + len.Println /* ERROR cannot select on len */ + len.Println /* ERROR cannot select on len */ () + _ = len.Println /* ERROR cannot select on len */ + _ = len /* ERROR cannot index len */ [0] + _ = *len /* ERROR cannot indirect len */ +} diff --git a/src/go/types/testdata/fixedbugs/issue51386.go2 b/src/go/types/testdata/fixedbugs/issue51386.go2 new file mode 100644 index 0000000000..ef6223927a --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue51386.go2 @@ -0,0 +1,17 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type myString string + +func _[P ~string | ~[]byte | ~[]rune]() { + _ = P("") + const s myString = "" + _ = P(s) +} + +func _[P myString]() { + _ = P("") +} diff --git a/src/go/types/type.go b/src/go/types/type.go index 323365aefe..130637530b 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -7,9 +7,7 @@ package types // 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. + // Underlying returns the underlying type of a type. Underlying() Type // String returns a string representation of a type. diff --git a/src/go/types/typeparam.go b/src/go/types/typeparam.go index 71e6861b87..778c687d43 100644 --- a/src/go/types/typeparam.go +++ b/src/go/types/typeparam.go @@ -35,6 +35,7 @@ func NewTypeParam(obj *TypeName, constraint Type) *TypeParam { return (*Checker)(nil).newTypeParam(obj, constraint) } +// check may be nil func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam { // Always increment lastID, even if it is not used. id := nextID() @@ -49,9 +50,7 @@ func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam { // iface may mutate typ.bound, so we must ensure that iface() is called // at least once before the resulting TypeParam escapes. if check != nil { - check.later(func() { - typ.iface() - }) + check.needsCleanup(typ) } else if constraint != nil { typ.iface() } @@ -95,9 +94,12 @@ func (t *TypeParam) String() string { return TypeString(t, nil) } // ---------------------------------------------------------------------------- // Implementation +func (t *TypeParam) cleanup() { + t.iface() + t.check = nil +} + // iface returns the constraint interface of t. -// TODO(gri) If we make tparamIsIface the default, this should be renamed to under -// (similar to Named.under). func (t *TypeParam) iface() *Interface { bound := t.bound @@ -138,16 +140,6 @@ func (t *TypeParam) iface() *Interface { return ityp } -// singleType returns the single type of the type parameter constraint; or nil. -func (t *TypeParam) singleType() Type { - return t.iface().typeSet().singleType() -} - -// hasTerms reports whether the type parameter constraint has specific type terms. -func (t *TypeParam) hasTerms() bool { - return t.iface().typeSet().hasTerms() -} - // is calls f with the specific type terms of t's constraint and reports whether // all calls to f returned true. If there are no specific terms, is // returns the result of f(nil). diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go index e1f73015b9..4c3f018cfe 100644 --- a/src/go/types/typeset.go +++ b/src/go/types/typeset.go @@ -37,7 +37,7 @@ func (s *_TypeSet) IsComparable(seen map[Type]bool) bool { return s.comparable } return s.is(func(t *term) bool { - return t != nil && comparable(t.typ, seen, nil) + return t != nil && comparable(t.typ, false, seen, nil) }) } @@ -101,9 +101,6 @@ func (s *_TypeSet) String() string { // hasTerms reports whether the type set has specific type terms. func (s *_TypeSet) hasTerms() bool { return !s.terms.isEmpty() && !s.terms.isAll() } -// singleType returns the single type in s if there is exactly one; otherwise the result is nil. -func (s *_TypeSet) singleType() Type { return s.terms.singleType() } - // subsetOf reports whether s1 ⊆ s2. func (s1 *_TypeSet) subsetOf(s2 *_TypeSet) bool { return s1.terms.subsetOf(s2.terms) } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index db6a904aaa..724c40963f 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -323,7 +323,7 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) { return typ case *ast.InterfaceType: - typ := new(Interface) + typ := check.newInterface() def.setUnderlying(typ) if def != nil { typ.obj = def.obj diff --git a/src/go/types/validtype.go b/src/go/types/validtype.go index c4ec2f2e0a..7d7029bce2 100644 --- a/src/go/types/validtype.go +++ b/src/go/types/validtype.go @@ -79,7 +79,7 @@ func (check *Checker) validType0(typ Type, env *tparamEnv, path []Object) typeIn // would have reported a type cycle and couldn't have been // imported in the first place. assert(t.obj.pkg == check.pkg) - t.underlying = Typ[Invalid] // t is in the current package (no race possibilty) + t.underlying = Typ[Invalid] // t is in the current package (no race possibility) // Find the starting point of the cycle and report it. for i, tn := range path { if tn == t.obj { diff --git a/src/net/net.go b/src/net/net.go index 77e54a9125..d91e743a01 100644 --- a/src/net/net.go +++ b/src/net/net.go @@ -703,6 +703,12 @@ var ( _ io.Reader = (*Buffers)(nil) ) +// WriteTo writes contents of the buffers to w. +// +// WriteTo implements io.WriterTo for Buffers. +// +// WriteTo modifies the slice v as well as v[i] for 0 <= i < len(v), +// but does not modify v[i][j] for any i, j. func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) { if wv, ok := w.(buffersWriter); ok { return wv.writeBuffers(v) @@ -719,6 +725,12 @@ func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) { return n, nil } +// Read from the buffers. +// +// Read implements io.Reader for Buffers. +// +// Read modifies the slice v as well as v[i] for 0 <= i < len(v), +// but does not modify v[i][j] for any i, j. func (v *Buffers) Read(p []byte) (n int, err error) { for len(p) > 0 && len(*v) > 0 { n0 := copy(p, (*v)[0]) diff --git a/src/reflect/asm_arm64.s b/src/reflect/asm_arm64.s index 5b9b3573fa..812b8a02c3 100644 --- a/src/reflect/asm_arm64.s +++ b/src/reflect/asm_arm64.s @@ -33,9 +33,14 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$432 ADD $LOCAL_REGARGS, RSP, R20 CALL runtime·spillArgs(SB) MOVD R26, 32(RSP) // outside of moveMakeFuncArgPtrs's arg area +#ifdef GOEXPERIMENT_regabiargs + MOVD R26, R0 + MOVD R20, R1 +#else MOVD R26, 8(RSP) MOVD R20, 16(RSP) - CALL ·moveMakeFuncArgPtrs(SB) +#endif + CALL ·moveMakeFuncArgPtrs(SB) MOVD 32(RSP), R26 MOVD R26, 8(RSP) MOVD $argframe+0(FP), R3 @@ -61,9 +66,14 @@ TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$432 ADD $LOCAL_REGARGS, RSP, R20 CALL runtime·spillArgs(SB) MOVD R26, 32(RSP) // outside of moveMakeFuncArgPtrs's arg area +#ifdef GOEXPERIMENT_regabiargs + MOVD R26, R0 + MOVD R20, R1 +#else MOVD R26, 8(RSP) MOVD R20, 16(RSP) - CALL ·moveMakeFuncArgPtrs(SB) +#endif + CALL ·moveMakeFuncArgPtrs(SB) MOVD 32(RSP), R26 MOVD R26, 8(RSP) MOVD $argframe+0(FP), R3 diff --git a/src/runtime/internal/atomic/atomic_arm.s b/src/runtime/internal/atomic/atomic_arm.s index be3fd3a395..92cbe8a34f 100644 --- a/src/runtime/internal/atomic/atomic_arm.s +++ b/src/runtime/internal/atomic/atomic_arm.s @@ -229,16 +229,22 @@ store64loop: // functions tail-call into the appropriate implementation, which // means they must not open a frame. Hence, when they go down the // panic path, at that point they push the LR to create a real frame -// (they don't need to pop it because panic won't return). +// (they don't need to pop it because panic won't return; however, we +// do need to set the SP delta back). + +// Check if R1 is 8-byte aligned, panic if not. +// Clobbers R2. +#define CHECK_ALIGN \ + AND.S $7, R1, R2 \ + BEQ 4(PC) \ + MOVW.W R14, -4(R13) /* prepare a real frame */ \ + BL ·panicUnaligned(SB) \ + ADD $4, R13 /* compensate SP delta */ TEXT ·Cas64(SB),NOSPLIT,$-4-21 NO_LOCAL_POINTERS MOVW addr+0(FP), R1 - // make unaligned atomic access panic - AND.S $7, R1, R2 - BEQ 3(PC) - MOVW.W R14, -4(R13) // prepare a real frame - BL ·panicUnaligned(SB) + CHECK_ALIGN MOVB runtime·goarm(SB), R11 CMP $7, R11 @@ -249,11 +255,7 @@ TEXT ·Cas64(SB),NOSPLIT,$-4-21 TEXT ·Xadd64(SB),NOSPLIT,$-4-20 NO_LOCAL_POINTERS MOVW addr+0(FP), R1 - // make unaligned atomic access panic - AND.S $7, R1, R2 - BEQ 3(PC) - MOVW.W R14, -4(R13) // prepare a real frame - BL ·panicUnaligned(SB) + CHECK_ALIGN MOVB runtime·goarm(SB), R11 CMP $7, R11 @@ -264,11 +266,7 @@ TEXT ·Xadd64(SB),NOSPLIT,$-4-20 TEXT ·Xchg64(SB),NOSPLIT,$-4-20 NO_LOCAL_POINTERS MOVW addr+0(FP), R1 - // make unaligned atomic access panic - AND.S $7, R1, R2 - BEQ 3(PC) - MOVW.W R14, -4(R13) // prepare a real frame - BL ·panicUnaligned(SB) + CHECK_ALIGN MOVB runtime·goarm(SB), R11 CMP $7, R11 @@ -279,11 +277,7 @@ TEXT ·Xchg64(SB),NOSPLIT,$-4-20 TEXT ·Load64(SB),NOSPLIT,$-4-12 NO_LOCAL_POINTERS MOVW addr+0(FP), R1 - // make unaligned atomic access panic - AND.S $7, R1, R2 - BEQ 3(PC) - MOVW.W R14, -4(R13) // prepare a real frame - BL ·panicUnaligned(SB) + CHECK_ALIGN MOVB runtime·goarm(SB), R11 CMP $7, R11 @@ -294,11 +288,7 @@ TEXT ·Load64(SB),NOSPLIT,$-4-12 TEXT ·Store64(SB),NOSPLIT,$-4-12 NO_LOCAL_POINTERS MOVW addr+0(FP), R1 - // make unaligned atomic access panic - AND.S $7, R1, R2 - BEQ 3(PC) - MOVW.W R14, -4(R13) // prepare a real frame - BL ·panicUnaligned(SB) + CHECK_ALIGN MOVB runtime·goarm(SB), R11 CMP $7, R11 diff --git a/src/runtime/race_arm64.s b/src/runtime/race_arm64.s index 798e23294a..95fec0b9c6 100644 --- a/src/runtime/race_arm64.s +++ b/src/runtime/race_arm64.s @@ -188,8 +188,12 @@ ret: // func runtime·racefuncenter(pc uintptr) // Called from instrumented code. -TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8 +TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8 +#ifdef GOEXPERIMENT_regabiargs + MOVD R0, R9 // callpc +#else MOVD callpc+0(FP), R9 +#endif JMP racefuncenter<>(SB) // Common code for racefuncenter @@ -205,7 +209,7 @@ TEXT racefuncenter<>(SB), NOSPLIT, $0-0 // func runtime·racefuncexit() // Called from instrumented code. -TEXT runtime·racefuncexit(SB), NOSPLIT, $0-0 +TEXT runtime·racefuncexit(SB), NOSPLIT, $0-0 load_g MOVD g_racectx(g), R0 // race context // void __tsan_func_exit(ThreadState *thr); @@ -392,12 +396,12 @@ racecallatomic_ignore: // Addr is outside the good range. // Call __tsan_go_ignore_sync_begin to ignore synchronization during the atomic op. // An attempt to synchronize on the address would cause crash. - MOVD R9, R20 // remember the original function + MOVD R9, R21 // remember the original function MOVD $__tsan_go_ignore_sync_begin(SB), R9 load_g MOVD g_racectx(g), R0 // goroutine context BL racecall<>(SB) - MOVD R20, R9 // restore the original function + MOVD R21, R9 // restore the original function // Call the atomic function. // racecall will call LLVM race code which might clobber R28 (g) load_g @@ -424,10 +428,12 @@ TEXT runtime·racecall(SB), NOSPLIT, $0-0 JMP racecall<>(SB) // Switches SP to g0 stack and calls (R9). Arguments already set. -TEXT racecall<>(SB), NOSPLIT, $0-0 +// Clobbers R19, R20. +TEXT racecall<>(SB), NOSPLIT|NOFRAME, $0-0 MOVD g_m(g), R10 // Switch to g0 stack. MOVD RSP, R19 // callee-saved, preserved across the CALL + MOVD R30, R20 // callee-saved, preserved across the CALL MOVD m_g0(R10), R11 CMP R11, g BEQ call // already on g0 @@ -436,7 +442,7 @@ TEXT racecall<>(SB), NOSPLIT, $0-0 call: BL R9 MOVD R19, RSP - RET + JMP (R20) // C->Go callback thunk that allows to call runtime·racesymbolize from C code. // Direct Go->C race call has only switched SP, finish g->g0 switch by setting correct g. diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go index 80dd1a0378..58b3a9171c 100644 --- a/src/runtime/sys_darwin.go +++ b/src/runtime/sys_darwin.go @@ -17,87 +17,91 @@ import ( //go:linkname syscall_syscall syscall.syscall //go:nosplit -//go:cgo_unsafe_args func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { + args := struct{ fn, a1, a2, a3, r1, r2, err uintptr }{fn, a1, a2, a3, r1, r2, err} entersyscall() - libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall)), unsafe.Pointer(&args)) exitsyscall() - return + return args.r1, args.r2, args.err } func syscall() //go:linkname syscall_syscallX syscall.syscallX //go:nosplit -//go:cgo_unsafe_args func syscall_syscallX(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { + args := struct{ fn, a1, a2, a3, r1, r2, err uintptr }{fn, a1, a2, a3, r1, r2, err} entersyscall() - libcCall(unsafe.Pointer(abi.FuncPCABI0(syscallX)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscallX)), unsafe.Pointer(&args)) exitsyscall() - return + return args.r1, args.r2, args.err } func syscallX() //go:linkname syscall_syscall6 syscall.syscall6 //go:nosplit -//go:cgo_unsafe_args func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { + args := struct{ fn, a1, a2, a3, a4, a5, a6, r1, r2, err uintptr }{fn, a1, a2, a3, a4, a5, a6, r1, r2, err} entersyscall() - libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6)), unsafe.Pointer(&args)) exitsyscall() - return + return args.r1, args.r2, args.err } func syscall6() //go:linkname syscall_syscall6X syscall.syscall6X //go:nosplit -//go:cgo_unsafe_args func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { + args := struct{ fn, a1, a2, a3, a4, a5, a6, r1, r2, err uintptr }{fn, a1, a2, a3, a4, a5, a6, r1, r2, err} entersyscall() - libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6X)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6X)), unsafe.Pointer(&args)) exitsyscall() - return + return args.r1, args.r2, args.err } func syscall6X() //go:linkname syscall_syscallPtr syscall.syscallPtr //go:nosplit -//go:cgo_unsafe_args func syscall_syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { + args := struct{ fn, a1, a2, a3, r1, r2, err uintptr }{fn, a1, a2, a3, r1, r2, err} entersyscall() - libcCall(unsafe.Pointer(abi.FuncPCABI0(syscallPtr)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscallPtr)), unsafe.Pointer(&args)) exitsyscall() - return + return args.r1, args.r2, args.err } func syscallPtr() //go:linkname syscall_rawSyscall syscall.rawSyscall //go:nosplit -//go:cgo_unsafe_args func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { - libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall)), unsafe.Pointer(&fn)) - return + args := struct{ fn, a1, a2, a3, r1, r2, err uintptr }{fn, a1, a2, a3, r1, r2, err} + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall)), unsafe.Pointer(&args)) + return args.r1, args.r2, args.err } //go:linkname syscall_rawSyscall6 syscall.rawSyscall6 //go:nosplit -//go:cgo_unsafe_args func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { - libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6)), unsafe.Pointer(&fn)) - return + args := struct{ fn, a1, a2, a3, a4, a5, a6, r1, r2, err uintptr }{fn, a1, a2, a3, a4, a5, a6, r1, r2, err} + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6)), unsafe.Pointer(&args)) + return args.r1, args.r2, args.err } // syscallNoErr is used in crypto/x509 to call into Security.framework and CF. //go:linkname crypto_x509_syscall crypto/x509/internal/macos.syscall //go:nosplit -//go:cgo_unsafe_args -func crypto_x509_syscall(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1 uintptr) { +func crypto_x509_syscall(fn, a1, a2, a3, a4, a5 uintptr, f1 float64) (r1 uintptr) { + args := struct { + fn, a1, a2, a3, a4, a5 uintptr + f1 float64 + r1 uintptr + }{fn, a1, a2, a3, a4, a5, f1, r1} entersyscall() - libcCall(unsafe.Pointer(abi.FuncPCABI0(syscallNoErr)), unsafe.Pointer(&fn)) + libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall_x509)), unsafe.Pointer(&args)) exitsyscall() - return + return args.r1 } -func syscallNoErr() +func syscall_x509() // The *_trampoline functions convert from the Go calling convention to the C calling convention // and then call the underlying libc function. They are defined in sys_darwin_$ARCH.s. diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s index 5d89cda8e6..db4715d2b7 100644 --- a/src/runtime/sys_darwin_amd64.s +++ b/src/runtime/sys_darwin_amd64.s @@ -831,9 +831,10 @@ ok: POPQ BP RET -// syscallNoErr is like syscall6 but does not check for errors, and -// only returns one value, for use with standard C ABI library functions. -TEXT runtime·syscallNoErr(SB),NOSPLIT,$0 +// syscall_x509 is for crypto/x509. It is like syscall6 but does not check for errors, +// takes 5 uintptrs and 1 float64, and only returns one value, +// for use with standard C ABI functions. +TEXT runtime·syscall_x509(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP SUBQ $16, SP @@ -842,7 +843,7 @@ TEXT runtime·syscallNoErr(SB),NOSPLIT,$0 MOVQ (3*8)(DI), DX // a3 MOVQ (4*8)(DI), CX // a4 MOVQ (5*8)(DI), R8 // a5 - MOVQ (6*8)(DI), R9 // a6 + MOVQ (6*8)(DI), X0 // f1 MOVQ DI, (SP) MOVQ (1*8)(DI), DI // a1 XORL AX, AX // vararg: say "no float args" diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s index 96d2ed1076..e57ac53e10 100644 --- a/src/runtime/sys_darwin_arm64.s +++ b/src/runtime/sys_darwin_arm64.s @@ -736,9 +736,10 @@ TEXT runtime·syscall6X(SB),NOSPLIT,$0 ok: RET -// syscallNoErr is like syscall6 but does not check for errors, and -// only returns one value, for use with standard C ABI library functions. -TEXT runtime·syscallNoErr(SB),NOSPLIT,$0 +// syscall_x509 is for crypto/x509. It is like syscall6 but does not check for errors, +// takes 5 uintptrs and 1 float64, and only returns one value, +// for use with standard C ABI functions. +TEXT runtime·syscall_x509(SB),NOSPLIT,$0 SUB $16, RSP // push structure pointer MOVD R0, (RSP) @@ -747,7 +748,7 @@ TEXT runtime·syscallNoErr(SB),NOSPLIT,$0 MOVD 24(R0), R2 // a3 MOVD 32(R0), R3 // a4 MOVD 40(R0), R4 // a5 - MOVD 48(R0), R5 // a6 + FMOVD 48(R0), F0 // f1 MOVD 8(R0), R0 // a1 BL (R12) diff --git a/src/runtime/testdata/testprogcgo/aprof.go b/src/runtime/testdata/testprogcgo/aprof.go index c70d6333bb..16870144dd 100644 --- a/src/runtime/testdata/testprogcgo/aprof.go +++ b/src/runtime/testdata/testprogcgo/aprof.go @@ -10,7 +10,7 @@ package main // This is a regression test for issue 14599, where profiling fails when the // function is the first C function. Exported functions are the first C // functions, so we use an exported function. Exported functions are created in -// lexigraphical order of source files, so this file is named aprof.go to +// lexicographical order of source files, so this file is named aprof.go to // ensure its function is first. // extern void CallGoNop(); diff --git a/src/strings/builder.go b/src/strings/builder.go index 547e52e84d..ba4df618bf 100644 --- a/src/strings/builder.go +++ b/src/strings/builder.go @@ -17,10 +17,9 @@ type Builder struct { buf []byte } -// noescape hides a pointer from escape analysis. noescape is -// the identity function but escape analysis doesn't think the -// output depends on the input. noescape is inlined and currently -// compiles down to zero instructions. +// noescape hides a pointer from escape analysis. It is the identity function +// but escape analysis doesn't think the output depends on the input. +// noescape is inlined and currently compiles down to zero instructions. // USE CAREFULLY! // This was copied from the runtime; see issues 23382 and 7921. //go:nosplit diff --git a/test/typeparam/issue51219.dir/a.go b/test/typeparam/issue51219.dir/a.go new file mode 100644 index 0000000000..29670df0d3 --- /dev/null +++ b/test/typeparam/issue51219.dir/a.go @@ -0,0 +1,20 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +// Type I is the first basic test for the issue, which relates to a type that is recursive +// via a type constraint. (In this test, I -> IConstraint -> MyStruct -> I.) +type JsonRaw []byte + +type MyStruct struct { + x *I[JsonRaw] +} + +type IConstraint interface { + JsonRaw | MyStruct +} + +type I[T IConstraint] struct { +} diff --git a/test/typeparam/issue51219.dir/main.go b/test/typeparam/issue51219.dir/main.go new file mode 100644 index 0000000000..999b4a96a1 --- /dev/null +++ b/test/typeparam/issue51219.dir/main.go @@ -0,0 +1,16 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" + "fmt" +) + +func main() { + var x a.I[a.JsonRaw] + + fmt.Printf("%v\n", x) +} diff --git a/test/typeparam/issue51219.go b/test/typeparam/issue51219.go new file mode 100644 index 0000000000..642f4bf49f --- /dev/null +++ b/test/typeparam/issue51219.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue51219.out b/test/typeparam/issue51219.out new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/test/typeparam/issue51219.out @@ -0,0 +1 @@ +{} diff --git a/test/typeparam/issue51219b.dir/a.go b/test/typeparam/issue51219b.dir/a.go new file mode 100644 index 0000000000..19049406a6 --- /dev/null +++ b/test/typeparam/issue51219b.dir/a.go @@ -0,0 +1,37 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type Interaction[DataT InteractionDataConstraint] struct { +} + +type InteractionDataConstraint interface { + []byte | + UserCommandInteractionData +} + +type UserCommandInteractionData struct { + resolvedInteractionWithOptions +} + +type resolvedInteractionWithOptions struct { + Resolved Resolved `json:"resolved,omitempty"` +} + +type Resolved struct { + Users ResolvedData[User] `json:"users,omitempty"` +} + +type ResolvedData[T ResolvedDataConstraint] map[uint64]T + +type ResolvedDataConstraint interface { + User | Message +} + +type User struct{} + +type Message struct { + Interaction *Interaction[[]byte] `json:"interaction,omitempty"` +} diff --git a/test/typeparam/issue51219b.dir/b.go b/test/typeparam/issue51219b.dir/b.go new file mode 100644 index 0000000000..8413d666b7 --- /dev/null +++ b/test/typeparam/issue51219b.dir/b.go @@ -0,0 +1,14 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import ( + "./a" +) + +// InteractionRequest is an incoming request Interaction +type InteractionRequest[T a.InteractionDataConstraint] struct { + a.Interaction[T] +} diff --git a/test/typeparam/issue51219b.dir/p.go b/test/typeparam/issue51219b.dir/p.go new file mode 100644 index 0000000000..9f8b840d48 --- /dev/null +++ b/test/typeparam/issue51219b.dir/p.go @@ -0,0 +1,14 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +import ( + "./b" +) + +// ResponseWriterMock mocks corde's ResponseWriter interface +type ResponseWriterMock struct { + x b.InteractionRequest[[]byte] +} diff --git a/test/typeparam/issue51219b.go b/test/typeparam/issue51219b.go new file mode 100644 index 0000000000..060a1214cc --- /dev/null +++ b/test/typeparam/issue51219b.go @@ -0,0 +1,7 @@ +// compiledir -G=3 + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored diff --git a/test/typeparam/issue51232.go b/test/typeparam/issue51232.go new file mode 100644 index 0000000000..2272dcdfcd --- /dev/null +++ b/test/typeparam/issue51232.go @@ -0,0 +1,31 @@ +// compile -G=3 + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type RC[RG any] interface { + ~[]RG +} + +type Fn[RCT RC[RG], RG any] func(RCT) + +type F[RCT RC[RG], RG any] interface { + Fn() Fn[RCT] +} + +type concreteF[RCT RC[RG], RG any] struct { + makeFn func() Fn[RCT] +} + +func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { + return c.makeFn() +} + +func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] { + return &concreteF[RCT]{ + makeFn: nil, + } +} diff --git a/test/typeparam/issue51233.go b/test/typeparam/issue51233.go new file mode 100644 index 0000000000..523f0b34d6 --- /dev/null +++ b/test/typeparam/issue51233.go @@ -0,0 +1,22 @@ +// compile -G=3 + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package p + +type RC[RG any] interface { + ~[]RG +} +type Fn[RCT RC[RG], RG any] func(RCT) +type FFn[RCT RC[RG], RG any] func() Fn[RCT] +type F[RCT RC[RG], RG any] interface { + Fn() Fn[RCT] +} +type concreteF[RCT RC[RG], RG any] struct { + makeFn FFn[RCT] +} + +func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { + return c.makeFn() +} diff --git a/test/typeparam/issue51236.go b/test/typeparam/issue51236.go new file mode 100644 index 0000000000..779c74ee6c --- /dev/null +++ b/test/typeparam/issue51236.go @@ -0,0 +1,22 @@ +// run -gcflags=-G=3 + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type I interface { + []byte +} + +func F[T I]() { + var t T + explodes(t) +} + +func explodes(b []byte) {} + +func main() { + +} diff --git a/test/typeparam/issue51245.go b/test/typeparam/issue51245.go new file mode 100644 index 0000000000..bd4f7c5dc9 --- /dev/null +++ b/test/typeparam/issue51245.go @@ -0,0 +1,16 @@ +// build -gcflags=-G=3 + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type T[P any] int +const C T[int] = 3 + +type T2 int +const C2 T2 = 9 + +func main() { +} diff --git a/test/typeparam/issue51303.go b/test/typeparam/issue51303.go new file mode 100644 index 0000000000..5f4bdc0634 --- /dev/null +++ b/test/typeparam/issue51303.go @@ -0,0 +1,65 @@ +// run -gcflags=-G=3 + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" +) + +func main() { + x := [][]int{{1}} + y := [][]int{{2, 3}} + IntersectSS(x, y) +} + +type list[E any] interface { + ~[]E + Equal(x, y E) bool +} + +// ss is a set of sets +type ss[E comparable, T []E] []T + +func (ss[E, T]) Equal(a, b T) bool { + return SetEq(a, b) +} + +func IntersectSS[E comparable](x, y [][]E) [][]E { + return IntersectT[[]E, ss[E, []E]](ss[E, []E](x), ss[E, []E](y)) +} + +func IntersectT[E any, L list[E]](x, y L) L { + var z L +outer: + for _, xe := range x { + fmt.Println("xe", xe) + for _, ye := range y { + fmt.Println("ye", ye) + fmt.Println("x", x) + if x.Equal(xe, ye) { + fmt.Println("appending") + z = append(z, xe) + continue outer + } + } + } + return z +} + +func SetEq[S []E, E comparable](x, y S) bool { + fmt.Println("SetEq", x, y) +outer: + for _, xe := range x { + for _, ye := range y { + if xe == ye { + continue outer + } + } + return false // xs wasn't found in y + } + return true +} diff --git a/test/typeparam/issue51303.out b/test/typeparam/issue51303.out new file mode 100644 index 0000000000..34b3be32dd --- /dev/null +++ b/test/typeparam/issue51303.out @@ -0,0 +1,4 @@ +xe [1] +ye [2 3] +x [[1]] +SetEq [1] [2 3] diff --git a/test/typeparam/issue51355.go b/test/typeparam/issue51355.go new file mode 100644 index 0000000000..15ffa4ba21 --- /dev/null +++ b/test/typeparam/issue51355.go @@ -0,0 +1,31 @@ +// compile -G=3 + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Cache[E comparable] struct { + adder func(...E) +} + +func New[E comparable]() *Cache[E] { + c := &Cache[E]{} + + c.adder = func(elements ...E) { + for _, value := range elements { + value := value + go func() { + println(value) + }() + } + } + + return c +} + +func main() { + c := New[string]() + c.adder("test") +} diff --git a/test/typeparam/issue51367.dir/a.go b/test/typeparam/issue51367.dir/a.go new file mode 100644 index 0000000000..be0c3b0688 --- /dev/null +++ b/test/typeparam/issue51367.dir/a.go @@ -0,0 +1,14 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type A[T any] struct{} + +func (_ A[T]) Method() {} + +func DoSomething[P any]() { + a := A[*byte]{} + a.Method() +} diff --git a/test/typeparam/issue51367.dir/main.go b/test/typeparam/issue51367.dir/main.go new file mode 100644 index 0000000000..64273d313b --- /dev/null +++ b/test/typeparam/issue51367.dir/main.go @@ -0,0 +1,13 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "a" +) + +func main() { + a.DoSomething[byte]() +} diff --git a/test/typeparam/issue51367.go b/test/typeparam/issue51367.go new file mode 100644 index 0000000000..642f4bf49f --- /dev/null +++ b/test/typeparam/issue51367.go @@ -0,0 +1,7 @@ +// rundir -G=3 + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ignored