[dev.boringcrypto.go1.18] all: merge go1.18 into dev.boringcrypto.go1.18

Change-Id: Ib2bfa4940b7b054d54f8ee998c63beb32c6afd51
This commit is contained in:
Heschi Kreinick 2022-03-15 12:16:46 -04:00
commit 0622ea4d90
405 changed files with 8575 additions and 3182 deletions

View File

@ -120,6 +120,7 @@ Alex Kohler <alexjohnkohler@gmail.com>
Alex Myasoedov <msoedov@gmail.com> Alex Myasoedov <msoedov@gmail.com>
Alex Opie <amtopie@gmail.com> Alex Opie <amtopie@gmail.com>
Alex Plugaru <alex@plugaru.org> <alexandru.plugaru@gmail.com> Alex Plugaru <alex@plugaru.org> <alexandru.plugaru@gmail.com>
Alex Schade <39062967+aschade92@users.noreply.github.com>
Alex Schroeder <alex@gnu.org> Alex Schroeder <alex@gnu.org>
Alex Sergeyev <abc@alexsergeyev.com> Alex Sergeyev <abc@alexsergeyev.com>
Alex Tokarev <aleksator@gmail.com> Alex Tokarev <aleksator@gmail.com>
@ -135,6 +136,7 @@ Alexander Klauer <Alexander.Klauer@googlemail.com>
Alexander Kucherenko <alxkchr@gmail.com> Alexander Kucherenko <alxkchr@gmail.com>
Alexander Larsson <alexander.larsson@gmail.com> Alexander Larsson <alexander.larsson@gmail.com>
Alexander Lourier <aml@rulezz.ru> Alexander Lourier <aml@rulezz.ru>
Alexander Melentyev <alexander@melentyev.org>
Alexander Menzhinsky <amenzhinsky@gmail.com> Alexander Menzhinsky <amenzhinsky@gmail.com>
Alexander Morozov <lk4d4math@gmail.com> Alexander Morozov <lk4d4math@gmail.com>
Alexander Neumann <alexander@bumpern.de> Alexander Neumann <alexander@bumpern.de>
@ -145,6 +147,7 @@ Alexander Polcyn <apolcyn@google.com>
Alexander Rakoczy <alex@golang.org> Alexander Rakoczy <alex@golang.org>
Alexander Reece <awreece@gmail.com> Alexander Reece <awreece@gmail.com>
Alexander Surma <surma@surmair.de> Alexander Surma <surma@surmair.de>
Alexander Yastrebov <yastrebov.alex@gmail.com>
Alexander Zhavnerchik <alex.vizor@gmail.com> Alexander Zhavnerchik <alex.vizor@gmail.com>
Alexander Zillion <alex@alexzillion.com> Alexander Zillion <alex@alexzillion.com>
Alexander Zolotov <goldifit@gmail.com> Alexander Zolotov <goldifit@gmail.com>
@ -179,6 +182,7 @@ Alok Menghrajani <alok.menghrajani@gmail.com>
Alwin Doss <alwindoss84@gmail.com> Alwin Doss <alwindoss84@gmail.com>
Aman Gupta <aman@tmm1.net> Aman Gupta <aman@tmm1.net>
Amarjeet Anand <amarjeetanandsingh@gmail.com> Amarjeet Anand <amarjeetanandsingh@gmail.com>
Amelia Downs <adowns@vmware.com>
Amir Mohammad Saied <amir@gluegadget.com> Amir Mohammad Saied <amir@gluegadget.com>
Amit Kumar <mittalmailbox@gmail.com> Amit Kumar <mittalmailbox@gmail.com>
Amr Mohammed <merodiro@gmail.com> Amr Mohammed <merodiro@gmail.com>
@ -191,6 +195,7 @@ Anatol Pomozov <anatol.pomozov@gmail.com>
Anders Pearson <anders@columbia.edu> Anders Pearson <anders@columbia.edu>
Anderson Queiroz <contato@andersonq.eti.br> Anderson Queiroz <contato@andersonq.eti.br>
André Carvalho <asantostc@gmail.com> André Carvalho <asantostc@gmail.com>
Andre Marianiello <andremarianiello@users.noreply.github.com>
André Martins <aanm90@gmail.com> André Martins <aanm90@gmail.com>
Andre Nathan <andrenth@gmail.com> Andre Nathan <andrenth@gmail.com>
Andrea Nodari <andrea.nodari91@gmail.com> Andrea Nodari <andrea.nodari91@gmail.com>
@ -221,6 +226,7 @@ Andrew Gerrand <adg@golang.org>
Andrew Harding <andrew@spacemonkey.com> Andrew Harding <andrew@spacemonkey.com>
Andrew Jackura <ajackura@google.com> Andrew Jackura <ajackura@google.com>
Andrew Kemm <andrewkemm@gmail.com> Andrew Kemm <andrewkemm@gmail.com>
Andrew LeFevre <capnspacehook@gmail.com>
Andrew Louis <alouis@digitalocean.com> Andrew Louis <alouis@digitalocean.com>
Andrew Lutomirski <andy@luto.us> Andrew Lutomirski <andy@luto.us>
Andrew Medvedev <andrew.y.medvedev@gmail.com> Andrew Medvedev <andrew.y.medvedev@gmail.com>
@ -234,6 +240,7 @@ Andrew Stormont <astormont@racktopsystems.com>
Andrew Stribblehill <ads@wompom.org> Andrew Stribblehill <ads@wompom.org>
Andrew Szeto <andrew@jabagawee.com> Andrew Szeto <andrew@jabagawee.com>
Andrew Todd <andrew.todd@wework.com> Andrew Todd <andrew.todd@wework.com>
Andrew Wansink <wansink@uber.com>
Andrew Werner <andrew@upthere.com> <awerner32@gmail.com> Andrew Werner <andrew@upthere.com> <awerner32@gmail.com>
Andrew Wilkins <axwalk@gmail.com> Andrew Wilkins <axwalk@gmail.com>
Andrew Williams <williams.andrew@gmail.com> Andrew Williams <williams.andrew@gmail.com>
@ -283,6 +290,7 @@ Antonio Bibiano <antbbn@gmail.com>
Antonio Garcia <garcia.olais@gmail.com> Antonio Garcia <garcia.olais@gmail.com>
Antonio Huete Jimenez <tuxillo@quantumachine.net> Antonio Huete Jimenez <tuxillo@quantumachine.net>
Antonio Murdaca <runcom@redhat.com> Antonio Murdaca <runcom@redhat.com>
Antonio Ojea <antonio.ojea.garcia@gmail.com>
Antonio Troina <thoeni@gmail.com> Antonio Troina <thoeni@gmail.com>
Anze Kolar <me@akolar.com> Anze Kolar <me@akolar.com>
Aofei Sheng <aofei@aofeisheng.com> Aofei Sheng <aofei@aofeisheng.com>
@ -290,6 +298,7 @@ Apisak Darakananda <pongad@gmail.com>
Aram Hăvărneanu <aram@mgk.ro> Aram Hăvărneanu <aram@mgk.ro>
Araragi Hokuto <kanseihonbucho@protonmail.com> Araragi Hokuto <kanseihonbucho@protonmail.com>
Arash Bina <arash@arash.io> Arash Bina <arash@arash.io>
Archana Ravindar <aravind5@in.ibm.com>
Arda Güçlü <ardaguclu@gmail.com> Arda Güçlü <ardaguclu@gmail.com>
Areski Belaid <areski@gmail.com> Areski Belaid <areski@gmail.com>
Ariel Mashraki <ariel@mashraki.co.il> Ariel Mashraki <ariel@mashraki.co.il>
@ -299,6 +308,7 @@ Arnaud Ysmal <arnaud.ysmal@gmail.com>
Arne Hormann <arnehormann@gmail.com> Arne Hormann <arnehormann@gmail.com>
Arnout Engelen <arnout@bzzt.net> Arnout Engelen <arnout@bzzt.net>
Aron Nopanen <aron.nopanen@gmail.com> Aron Nopanen <aron.nopanen@gmail.com>
Arran Walker <arran.walker@fiveturns.org>
Artem Alekseev <artem.alekseev@intel.com> Artem Alekseev <artem.alekseev@intel.com>
Artem Khvastunov <artem.khvastunov@jetbrains.com> Artem Khvastunov <artem.khvastunov@jetbrains.com>
Artem Kolin <artemkaxboy@gmail.com> Artem Kolin <artemkaxboy@gmail.com>
@ -337,6 +347,7 @@ Balaram Makam <bmakam.qdt@qualcommdatacenter.com>
Balazs Lecz <leczb@google.com> Balazs Lecz <leczb@google.com>
Baokun Lee <nototon@gmail.com> <bk@golangcn.org> Baokun Lee <nototon@gmail.com> <bk@golangcn.org>
Barnaby Keene <accounts@southcla.ws> Barnaby Keene <accounts@southcla.ws>
Bartłomiej Klimczak <bartlomiej.klimczak88@gmail.com>
Bartosz Grzybowski <melkorm@gmail.com> Bartosz Grzybowski <melkorm@gmail.com>
Bartosz Oler <brtsz@google.com> Bartosz Oler <brtsz@google.com>
Bassam Ojeil <bojeil@google.com> Bassam Ojeil <bojeil@google.com>
@ -368,6 +379,7 @@ Benny Siegert <bsiegert@gmail.com>
Benoit Sigoure <tsunanet@gmail.com> Benoit Sigoure <tsunanet@gmail.com>
Berengar Lehr <Berengar.Lehr@gmx.de> Berengar Lehr <Berengar.Lehr@gmx.de>
Berkant Ipek <41230766+0xbkt@users.noreply.github.com> Berkant Ipek <41230766+0xbkt@users.noreply.github.com>
Beth Brown <ecbrown@google.com>
Bharath Kumar Uppala <uppala.bharath@gmail.com> Bharath Kumar Uppala <uppala.bharath@gmail.com>
Bharath Thiruveedula <tbharath91@gmail.com> Bharath Thiruveedula <tbharath91@gmail.com>
Bhavin Gandhi <bhavin7392@gmail.com> Bhavin Gandhi <bhavin7392@gmail.com>
@ -430,6 +442,7 @@ Brian Ketelsen <bketelsen@gmail.com>
Brian Slesinsky <skybrian@google.com> Brian Slesinsky <skybrian@google.com>
Brian Smith <ohohvi@gmail.com> Brian Smith <ohohvi@gmail.com>
Brian Starke <brian.starke@gmail.com> Brian Starke <brian.starke@gmail.com>
Bruce Huang <helbingxxx@gmail.com>
Bryan Alexander <Kozical@msn.com> Bryan Alexander <Kozical@msn.com>
Bryan Boreham <bjboreham@gmail.com> Bryan Boreham <bjboreham@gmail.com>
Bryan C. Mills <bcmills@google.com> Bryan C. Mills <bcmills@google.com>
@ -482,17 +495,21 @@ Charles Kenney <charlesc.kenney@gmail.com>
Charles L. Dorian <cldorian@gmail.com> Charles L. Dorian <cldorian@gmail.com>
Charles Lee <zombie.fml@gmail.com> Charles Lee <zombie.fml@gmail.com>
Charles Weill <weill@google.com> Charles Weill <weill@google.com>
Charlie Getzen <charlie@bolt.com>
Charlie Moog <moogcharlie@gmail.com> Charlie Moog <moogcharlie@gmail.com>
Charlotte Brandhorst-Satzkorn <catzkorn@gmail.com> Charlotte Brandhorst-Satzkorn <catzkorn@gmail.com>
Chauncy Cullitan <chauncyc@google.com> Chauncy Cullitan <chauncyc@google.com>
Chen Zhidong <njutczd@gmail.com> Chen Zhidong <njutczd@gmail.com>
Chen Zhihan <energiehund@gmail.com> Chen Zhihan <energiehund@gmail.com>
Cheng Wang <wangchengiscool@gmail.com>
Cherry Mui <cherryyz@google.com> Cherry Mui <cherryyz@google.com>
Chew Choon Keat <choonkeat@gmail.com> Chew Choon Keat <choonkeat@gmail.com>
Chia-Chi Hsu <wuchi5457@gmail.com>
Chiawen Chen <golopot@gmail.com> Chiawen Chen <golopot@gmail.com>
Chirag Sukhala <cchirag77@gmail.com> Chirag Sukhala <cchirag77@gmail.com>
Cholerae Hu <choleraehyq@gmail.com> Cholerae Hu <choleraehyq@gmail.com>
Chotepud Teo <AlexRouSg@users.noreply.github.com> Chotepud Teo <AlexRouSg@users.noreply.github.com>
Chressie Himpel <chressie@google.com>
Chris Ball <chris@printf.net> Chris Ball <chris@printf.net>
Chris Biscardi <chris@christopherbiscardi.com> Chris Biscardi <chris@christopherbiscardi.com>
Chris Broadfoot <cbro@golang.org> Chris Broadfoot <cbro@golang.org>
@ -570,6 +587,7 @@ Cuong Manh Le <cuong@orijtech.com>
Curtis La Graff <curtis@lagraff.me> Curtis La Graff <curtis@lagraff.me>
Cyrill Schumacher <cyrill@schumacher.fm> Cyrill Schumacher <cyrill@schumacher.fm>
Dai Jie <gzdaijie@gmail.com> Dai Jie <gzdaijie@gmail.com>
Dai Wentao <dwt136@gmail.com>
Daisuke Fujita <dtanshi45@gmail.com> Daisuke Fujita <dtanshi45@gmail.com>
Daisuke Suzuki <daisuzu@gmail.com> Daisuke Suzuki <daisuzu@gmail.com>
Daker Fernandes Pinheiro <daker.fernandes.pinheiro@intel.com> Daker Fernandes Pinheiro <daker.fernandes.pinheiro@intel.com>
@ -603,6 +621,7 @@ Daniel Langner <s8572327@gmail.com>
Daniel Lidén <daniel.liden.87@gmail.com> Daniel Lidén <daniel.liden.87@gmail.com>
Daniel Lublin <daniel@lublin.se> Daniel Lublin <daniel@lublin.se>
Daniel Mangum <georgedanielmangum@gmail.com> Daniel Mangum <georgedanielmangum@gmail.com>
Daniel Marshall <daniel.marshall2@ibm.com>
Daniel Martí <mvdan@mvdan.cc> Daniel Martí <mvdan@mvdan.cc>
Daniel McCarney <cpu@letsencrypt.org> Daniel McCarney <cpu@letsencrypt.org>
Daniel Morsing <daniel.morsing@gmail.com> Daniel Morsing <daniel.morsing@gmail.com>
@ -727,6 +746,7 @@ Dmitry Mottl <dmitry.mottl@gmail.com>
Dmitry Neverov <dmitry.neverov@gmail.com> Dmitry Neverov <dmitry.neverov@gmail.com>
Dmitry Savintsev <dsavints@gmail.com> Dmitry Savintsev <dsavints@gmail.com>
Dmitry Yakunin <nonamezeil@gmail.com> Dmitry Yakunin <nonamezeil@gmail.com>
Dmytro Shynkevych <dm.shynk@gmail.com>
Doga Fincan <doga@icloud.com> Doga Fincan <doga@icloud.com>
Domas Tamašauskas <puerdomus@gmail.com> Domas Tamašauskas <puerdomus@gmail.com>
Domen Ipavec <domen@ipavec.net> Domen Ipavec <domen@ipavec.net>
@ -751,6 +771,7 @@ Dustin Herbison <djherbis@gmail.com>
Dustin Long <dustmop@gmail.com> Dustin Long <dustmop@gmail.com>
Dustin Sallings <dsallings@gmail.com> Dustin Sallings <dsallings@gmail.com>
Dustin Shields-Cloues <dcloues@gmail.com> Dustin Shields-Cloues <dcloues@gmail.com>
Dustin Spicuzza <dustin.spicuzza@gmail.com>
Dvir Volk <dvir@everything.me> <dvirsky@gmail.com> Dvir Volk <dvir@everything.me> <dvirsky@gmail.com>
Dylan Waits <dylan@waits.io> Dylan Waits <dylan@waits.io>
Ed Schouten <ed@nuxi.nl> Ed Schouten <ed@nuxi.nl>
@ -810,9 +831,11 @@ Erin Masatsugu <erin.masatsugu@gmail.com>
Ernest Chiang <ernest_chiang@htc.com> Ernest Chiang <ernest_chiang@htc.com>
Erwin Oegema <blablaechthema@hotmail.com> Erwin Oegema <blablaechthema@hotmail.com>
Esko Luontola <esko.luontola@gmail.com> Esko Luontola <esko.luontola@gmail.com>
Ethan Anderson <eanderson@atlassian.com>
Ethan Burns <eaburns@google.com> Ethan Burns <eaburns@google.com>
Ethan Hur <ethan0311@gmail.com> Ethan Hur <ethan0311@gmail.com>
Ethan Miller <eamiller@us.ibm.com> Ethan Miller <eamiller@us.ibm.com>
Ethan Reesor <ethan.reesor@gmail.com>
Euan Kemp <euank@euank.com> Euan Kemp <euank@euank.com>
Eugene Formanenko <mo4islona@gmail.com> Eugene Formanenko <mo4islona@gmail.com>
Eugene Kalinin <e.v.kalinin@gmail.com> Eugene Kalinin <e.v.kalinin@gmail.com>
@ -831,8 +854,10 @@ Evgeniy Polyakov <zbr@ioremap.net>
Ewan Chou <coocood@gmail.com> Ewan Chou <coocood@gmail.com>
Ewan Valentine <ewan.valentine89@gmail.com> Ewan Valentine <ewan.valentine89@gmail.com>
Eyal Posener <posener@gmail.com> Eyal Posener <posener@gmail.com>
F. Talha Altınel <talhaaltinel@hotmail.com>
Fabian Wickborn <fabian@wickborn.net> Fabian Wickborn <fabian@wickborn.net>
Fabian Zaremba <fabian@youremail.eu> Fabian Zaremba <fabian@youremail.eu>
Fabio Falzoi <fabio.falzoi84@gmail.com>
Fabrizio Milo <mistobaan@gmail.com> Fabrizio Milo <mistobaan@gmail.com>
Faiyaz Ahmed <ahmedf@vmware.com> Faiyaz Ahmed <ahmedf@vmware.com>
Fan Hongjian <fan.howard@gmail.com> Fan Hongjian <fan.howard@gmail.com>
@ -861,21 +886,25 @@ Firmansyah Adiputra <frm.adiputra@gmail.com>
Florian Forster <octo@google.com> Florian Forster <octo@google.com>
Florian Uekermann <florian@uekermann-online.de> <f1@uekermann-online.de> Florian Uekermann <florian@uekermann-online.de> <f1@uekermann-online.de>
Florian Weimer <fw@deneb.enyo.de> Florian Weimer <fw@deneb.enyo.de>
Florin Papa <fpapa@google.com>
Florin Patan <florinpatan@gmail.com> Florin Patan <florinpatan@gmail.com>
Folke Behrens <folke@google.com> Folke Behrens <folke@google.com>
Ford Hurley <ford.hurley@gmail.com> Ford Hurley <ford.hurley@gmail.com>
Forest Johnson <forest.n.johnson@gmail.com>
Francesc Campoy <campoy@golang.org> Francesc Campoy <campoy@golang.org>
Francesco Guardiani <francescoguard@gmail.com> Francesco Guardiani <francescoguard@gmail.com>
Francesco Renzi <rentziass@gmail.com> Francesco Renzi <rentziass@gmail.com>
Francisco Claude <fclaude@recoded.cl> Francisco Claude <fclaude@recoded.cl>
Francisco Rojas <francisco.rojas.gallegos@gmail.com> Francisco Rojas <francisco.rojas.gallegos@gmail.com>
Francisco Souza <franciscossouza@gmail.com> Francisco Souza <franciscossouza@gmail.com>
Frank Chiarulli Jr <frank@frankchiarulli.com>
Frank Schroeder <frank.schroeder@gmail.com> Frank Schroeder <frank.schroeder@gmail.com>
Frank Somers <fsomers@arista.com> Frank Somers <fsomers@arista.com>
Frederic Guillot <frederic.guillot@gmail.com> Frederic Guillot <frederic.guillot@gmail.com>
Frederick Kelly Mayle III <frederickmayle@gmail.com> Frederick Kelly Mayle III <frederickmayle@gmail.com>
Frederik Ring <frederik.ring@gmail.com> Frederik Ring <frederik.ring@gmail.com>
Frederik Zipp <fzipp@gmx.de> Frederik Zipp <fzipp@gmx.de>
Frediano Ziglio <freddy77@gmail.com>
Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com> Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
Fredrik Forsmo <fredrik.forsmo@gmail.com> Fredrik Forsmo <fredrik.forsmo@gmail.com>
Fredrik Wallgren <fredrik.wallgren@gmail.com> Fredrik Wallgren <fredrik.wallgren@gmail.com>
@ -914,6 +943,7 @@ Geon Kim <geon0250@gmail.com>
Georg Reinke <guelfey@gmail.com> Georg Reinke <guelfey@gmail.com>
George Gkirtsou <ggirtsou@gmail.com> George Gkirtsou <ggirtsou@gmail.com>
George Hartzell <hartzell@alerce.com> George Hartzell <hartzell@alerce.com>
George Looshch <looshch@loosh.ch>
George Shammas <george@shamm.as> <georgyo@gmail.com> George Shammas <george@shamm.as> <georgyo@gmail.com>
George Tsilias <tsiliasg@gmail.com> George Tsilias <tsiliasg@gmail.com>
Gerasimos (Makis) Maropoulos <kataras2006@hotmail.com> Gerasimos (Makis) Maropoulos <kataras2006@hotmail.com>
@ -954,19 +984,27 @@ GitHub User @fatedier (7346661) <fatedier@gmail.com>
GitHub User @frennkie (6499251) <mail@rhab.de> GitHub User @frennkie (6499251) <mail@rhab.de>
GitHub User @geedchin (11672310) <geedchin@gmail.com> GitHub User @geedchin (11672310) <geedchin@gmail.com>
GitHub User @GrigoriyMikhalkin (3637857) <grigoriymikhalkin@gmail.com> GitHub User @GrigoriyMikhalkin (3637857) <grigoriymikhalkin@gmail.com>
GitHub User @Gusted (25481501) <williamzijl7@hotmail.com>
GitHub User @hengwu0 (41297446) <41297446+hengwu0@users.noreply.github.com> GitHub User @hengwu0 (41297446) <41297446+hengwu0@users.noreply.github.com>
GitHub User @hitzhangjie (3725760) <hit.zhangjie@gmail.com> GitHub User @hitzhangjie (3725760) <hit.zhangjie@gmail.com>
GitHub User @hkhere (33268704) <33268704+hkhere@users.noreply.github.com>
GitHub User @hopehook (7326168) <hopehook.com@gmail.com>
GitHub User @hqpko (13887251) <whaibin01@hotmail.com> GitHub User @hqpko (13887251) <whaibin01@hotmail.com>
GitHub User @Illirgway (5428603) <illirgway@gmail.com>
GitHub User @itchyny (375258) <itchyny@hatena.ne.jp> GitHub User @itchyny (375258) <itchyny@hatena.ne.jp>
GitHub User @jinmiaoluo (39730824) <jinmiaoluo@icloud.com> GitHub User @jinmiaoluo (39730824) <jinmiaoluo@icloud.com>
GitHub User @jopbrown (6345470) <msshane2008@gmail.com> GitHub User @jopbrown (6345470) <msshane2008@gmail.com>
GitHub User @kazyshr (30496953) <kazyshr0301@gmail.com> GitHub User @kazyshr (30496953) <kazyshr0301@gmail.com>
GitHub User @kc1212 (1093806) <kc1212@users.noreply.github.com> GitHub User @kc1212 (1093806) <kc1212@users.noreply.github.com>
GitHub User @komisan19 (18901496) <komiyama6219@gmail.com> GitHub User @komisan19 (18901496) <komiyama6219@gmail.com>
GitHub User @korzhao (64203902) <korzhao95@gmail.com>
GitHub User @Kropekk (13366453) <kamilkropiewnicki@gmail.com> GitHub User @Kropekk (13366453) <kamilkropiewnicki@gmail.com>
GitHub User @lgbgbl (65756378) <lgbgbl@qq.com>
GitHub User @lhl2617 (33488131) <l.h.lee2617@gmail.com> GitHub User @lhl2617 (33488131) <l.h.lee2617@gmail.com>
GitHub User @linguohua (3434367) <lghchinaidea@gmail.com> GitHub User @linguohua (3434367) <lghchinaidea@gmail.com>
GitHub User @lloydchang (1329685) <lloydchang@gmail.com>
GitHub User @LotusFenn (13775899) <fenn.lotus@gmail.com> GitHub User @LotusFenn (13775899) <fenn.lotus@gmail.com>
GitHub User @luochuanhang (96416201) <chuanhangluo@gmail.com>
GitHub User @ly303550688 (11519839) <yang.liu636@gmail.com> GitHub User @ly303550688 (11519839) <yang.liu636@gmail.com>
GitHub User @madiganz (18340029) <zacharywmadigan@gmail.com> GitHub User @madiganz (18340029) <zacharywmadigan@gmail.com>
GitHub User @maltalex (10195391) <code@bit48.net> GitHub User @maltalex (10195391) <code@bit48.net>
@ -976,6 +1014,7 @@ GitHub User @micnncim (21333876) <micnncim@gmail.com>
GitHub User @mkishere (224617) <224617+mkishere@users.noreply.github.com> GitHub User @mkishere (224617) <224617+mkishere@users.noreply.github.com>
GitHub User @nu50218 (40682920) <nu_ll@icloud.com> GitHub User @nu50218 (40682920) <nu_ll@icloud.com>
GitHub User @OlgaVlPetrova (44112727) <OVPpetrova@gmail.com> GitHub User @OlgaVlPetrova (44112727) <OVPpetrova@gmail.com>
GitHub User @pierwill (19642016) <pierwill@users.noreply.github.com>
GitHub User @pityonline (438222) <pityonline@gmail.com> GitHub User @pityonline (438222) <pityonline@gmail.com>
GitHub User @po3rin (29445112) <abctail30@gmail.com> GitHub User @po3rin (29445112) <abctail30@gmail.com>
GitHub User @pokutuna (57545) <popopopopokutuna@gmail.com> GitHub User @pokutuna (57545) <popopopopokutuna@gmail.com>
@ -983,13 +1022,18 @@ GitHub User @povsister (11040951) <pov@mahou-shoujo.moe>
GitHub User @pytimer (17105586) <lixin20101023@gmail.com> GitHub User @pytimer (17105586) <lixin20101023@gmail.com>
GitHub User @qcrao (7698088) <qcrao91@gmail.com> GitHub User @qcrao (7698088) <qcrao91@gmail.com>
GitHub User @ramenjuniti (32011829) <ramenjuniti@gmail.com> GitHub User @ramenjuniti (32011829) <ramenjuniti@gmail.com>
GitHub User @renthraysk (30576707) <renthraysk@gmail.com>
GitHub User @roudkerk (52280478) <roudkerk@google.com>
GitHub User @saitarunreddy (21041941) <saitarunreddypalla@gmail.com> GitHub User @saitarunreddy (21041941) <saitarunreddypalla@gmail.com>
GitHub User @SataQiu (9354727) <shidaqiu2018@gmail.com> GitHub User @SataQiu (9354727) <shidaqiu2018@gmail.com>
GitHub User @seifchen (23326132) <chenxuefeng1207@gmail.com>
GitHub User @shogo-ma (9860598) <Choroma194@gmail.com> GitHub User @shogo-ma (9860598) <Choroma194@gmail.com>
GitHub User @sivchari (55221074) <shibuuuu5@gmail.com> GitHub User @sivchari (55221074) <shibuuuu5@gmail.com>
GitHub User @skanehira (7888591) <sho19921005@gmail.com> GitHub User @skanehira (7888591) <sho19921005@gmail.com>
GitHub User @soolaugust (10558124) <soolaugust@gmail.com> GitHub User @soolaugust (10558124) <soolaugust@gmail.com>
GitHub User @surechen (7249331) <surechen17@gmail.com> GitHub User @surechen (7249331) <surechen17@gmail.com>
GitHub User @syumai (6882878) <syumai@gmail.com>
GitHub User @tangxi666 (48145175) <tx1275044634@gmail.com>
GitHub User @tatsumack (4510569) <tatsu.mack@gmail.com> GitHub User @tatsumack (4510569) <tatsu.mack@gmail.com>
GitHub User @tell-k (26263) <ffk2005@gmail.com> GitHub User @tell-k (26263) <ffk2005@gmail.com>
GitHub User @tennashi (10219626) <tennashio@gmail.com> GitHub User @tennashi (10219626) <tennashio@gmail.com>
@ -999,6 +1043,7 @@ GitHub User @unbyte (5772358) <i@shangyes.net>
GitHub User @uropek (39370426) <uropek@gmail.com> GitHub User @uropek (39370426) <uropek@gmail.com>
GitHub User @utkarsh-extc (53217283) <utkarsh.extc@gmail.com> GitHub User @utkarsh-extc (53217283) <utkarsh.extc@gmail.com>
GitHub User @witchard (4994659) <witchard@hotmail.co.uk> GitHub User @witchard (4994659) <witchard@hotmail.co.uk>
GitHub User @wmdngngng (22067700) <wangmingdong@gmail.com>
GitHub User @wolf1996 (5901874) <ksgiv37@gmail.com> GitHub User @wolf1996 (5901874) <ksgiv37@gmail.com>
GitHub User @yah01 (12216890) <kagaminehuan@gmail.com> GitHub User @yah01 (12216890) <kagaminehuan@gmail.com>
GitHub User @yuanhh (1298735) <yuan415030@gmail.com> GitHub User @yuanhh (1298735) <yuan415030@gmail.com>
@ -1029,12 +1074,14 @@ Guilherme Garnier <guilherme.garnier@gmail.com>
Guilherme Goncalves <guilhermeaugustosg@gmail.com> Guilherme Goncalves <guilhermeaugustosg@gmail.com>
Guilherme Rezende <guilhermebr@gmail.com> Guilherme Rezende <guilhermebr@gmail.com>
Guilherme Souza <32180229+gqgs@users.noreply.github.com> Guilherme Souza <32180229+gqgs@users.noreply.github.com>
Guillaume Blaquiere <guillaume.blaquiere@gmail.com>
Guillaume J. Charmes <guillaume@charmes.net> Guillaume J. Charmes <guillaume@charmes.net>
Guillaume Sottas <guillaumesottas@gmail.com> Guillaume Sottas <guillaumesottas@gmail.com>
Günther Noack <gnoack@google.com> Günther Noack <gnoack@google.com>
Guobiao Mei <meiguobiao@gmail.com> Guobiao Mei <meiguobiao@gmail.com>
Guodong Li <guodongli@google.com> Guodong Li <guodongli@google.com>
Guoliang Wang <iamwgliang@gmail.com> Guoliang Wang <iamwgliang@gmail.com>
Guoqi Chen <chenguoqi@loongson.cn>
Gustav Paul <gustav.paul@gmail.com> Gustav Paul <gustav.paul@gmail.com>
Gustav Westling <gustav@westling.xyz> Gustav Westling <gustav@westling.xyz>
Gustavo Franco <gustavorfranco@gmail.com> Gustavo Franco <gustavorfranco@gmail.com>
@ -1050,6 +1097,8 @@ Hang Qian <hangqian90@gmail.com>
Hanjun Kim <hallazzang@gmail.com> Hanjun Kim <hallazzang@gmail.com>
Hanlin He <hanling.he@gmail.com> Hanlin He <hanling.he@gmail.com>
Hanlin Shi <shihanlin9@gmail.com> Hanlin Shi <shihanlin9@gmail.com>
Hans Nielsen <hans@stackallocated.com>
Hao Mou <mouhao.mu@gmail.com>
Haoran Luo <haoran.luo@chaitin.com> Haoran Luo <haoran.luo@chaitin.com>
Haosdent Huang <haosdent@gmail.com> Haosdent Huang <haosdent@gmail.com>
Harald Nordgren <haraldnordgren@gmail.com> Harald Nordgren <haraldnordgren@gmail.com>
@ -1126,6 +1175,7 @@ Igor Zhilianin <igor.zhilianin@gmail.com>
Ikko Ashimine <eltociear@gmail.com> Ikko Ashimine <eltociear@gmail.com>
Illya Yalovyy <yalovoy@gmail.com> Illya Yalovyy <yalovoy@gmail.com>
Ilya Chukov <56119080+Elias506@users.noreply.github.com> Ilya Chukov <56119080+Elias506@users.noreply.github.com>
Ilya Mateyko <me@astrophena.name>
Ilya Sinelnikov <sidhmangh@gmail.com> Ilya Sinelnikov <sidhmangh@gmail.com>
Ilya Tocar <ilya.tocar@intel.com> Ilya Tocar <ilya.tocar@intel.com>
INADA Naoki <songofacandy@gmail.com> INADA Naoki <songofacandy@gmail.com>
@ -1157,6 +1207,7 @@ Jaana Burcu Dogan <jbd@google.com> <jbd@golang.org> <burcujdogan@gmail.com>
Jaap Aarts <jaap.aarts1@gmail.com> Jaap Aarts <jaap.aarts1@gmail.com>
Jack Britton <jackxbritton@gmail.com> Jack Britton <jackxbritton@gmail.com>
Jack Lindamood <jlindamo@justin.tv> Jack Lindamood <jlindamo@justin.tv>
Jack You <jamesyou@google.com>
Jacob Baskin <jbaskin@google.com> Jacob Baskin <jbaskin@google.com>
Jacob Blain Christen <dweomer5@gmail.com> Jacob Blain Christen <dweomer5@gmail.com>
Jacob H. Haven <jacob@cloudflare.com> Jacob H. Haven <jacob@cloudflare.com>
@ -1165,6 +1216,7 @@ Jacob Walker <jacobwalker0814@gmail.com>
Jaden Teng <long.asyn@gmail.com> Jaden Teng <long.asyn@gmail.com>
Jae Kwon <jae@tendermint.com> Jae Kwon <jae@tendermint.com>
Jake B <doogie1012@gmail.com> Jake B <doogie1012@gmail.com>
Jake Ciolek <jakub@ciolek.dev>
Jakob Borg <jakob@nym.se> Jakob Borg <jakob@nym.se>
Jakob Weisblat <jakobw@mit.edu> Jakob Weisblat <jakobw@mit.edu>
Jakub Čajka <jcajka@redhat.com> Jakub Čajka <jcajka@redhat.com>
@ -1183,6 +1235,7 @@ James Eady <jmeady@google.com>
James Fennell <jpfennell@google.com> James Fennell <jpfennell@google.com>
James Fysh <james.fysh@gmail.com> James Fysh <james.fysh@gmail.com>
James Gray <james@james4k.com> James Gray <james@james4k.com>
James Harris <mailjamesharris@gmail.com>
James Hartig <fastest963@gmail.com> James Hartig <fastest963@gmail.com>
James Kasten <jdkasten@google.com> James Kasten <jdkasten@google.com>
James Lawrence <jljatone@gmail.com> James Lawrence <jljatone@gmail.com>
@ -1246,6 +1299,7 @@ Jean de Klerk <deklerk@google.com>
Jean-André Santoni <jean.andre.santoni@gmail.com> Jean-André Santoni <jean.andre.santoni@gmail.com>
Jean-François Bustarret <jf@bustarret.com> Jean-François Bustarret <jf@bustarret.com>
Jean-Francois Cantin <jfcantin@gmail.com> Jean-Francois Cantin <jfcantin@gmail.com>
Jean-Hadrien Chabran <jh@chabran.fr>
Jean-Marc Eurin <jmeurin@google.com> Jean-Marc Eurin <jmeurin@google.com>
Jean-Nicolas Moal <jn.moal@gmail.com> Jean-Nicolas Moal <jn.moal@gmail.com>
Jed Denlea <jed@fastly.com> Jed Denlea <jed@fastly.com>
@ -1260,6 +1314,7 @@ Jeff Johnson <jrjohnson@google.com>
Jeff R. Allen <jra@nella.org> <jeff.allen@gmail.com> Jeff R. Allen <jra@nella.org> <jeff.allen@gmail.com>
Jeff Sickel <jas@corpus-callosum.com> Jeff Sickel <jas@corpus-callosum.com>
Jeff Wendling <jeff@spacemonkey.com> Jeff Wendling <jeff@spacemonkey.com>
Jeff Wentworth <j.wentworth@gmail.com>
Jeff Widman <jeff@jeffwidman.com> Jeff Widman <jeff@jeffwidman.com>
Jeffrey H <jeffreyh192@gmail.com> Jeffrey H <jeffreyh192@gmail.com>
Jelte Fennema <github-tech@jeltef.nl> Jelte Fennema <github-tech@jeltef.nl>
@ -1282,6 +1337,7 @@ Jesús Espino <jespinog@gmail.com>
Jia Zhan <jzhan@uber.com> Jia Zhan <jzhan@uber.com>
Jiacai Liu <jiacai2050@gmail.com> Jiacai Liu <jiacai2050@gmail.com>
Jiahao Lu <lujjjh@gmail.com> Jiahao Lu <lujjjh@gmail.com>
Jiahua Wang <wjh180909@gmail.com>
Jianing Yu <jnyu@google.com> Jianing Yu <jnyu@google.com>
Jianqiao Li <jianqiaoli@google.com> Jianqiao Li <jianqiaoli@google.com>
Jiayu Yi <yijiayu@gmail.com> Jiayu Yi <yijiayu@gmail.com>
@ -1298,10 +1354,12 @@ Jingcheng Zhang <diogin@gmail.com>
Jingguo Yao <yaojingguo@gmail.com> Jingguo Yao <yaojingguo@gmail.com>
Jingnan Si <jingnan.si@gmail.com> Jingnan Si <jingnan.si@gmail.com>
Jinkun Zhang <franksnolf@gmail.com> Jinkun Zhang <franksnolf@gmail.com>
Jinwen Wo <wojinwen@huawei.com>
Jiong Du <londevil@gmail.com> Jiong Du <londevil@gmail.com>
Jirka Daněk <dnk@mail.muni.cz> Jirka Daněk <dnk@mail.muni.cz>
Jiulong Wang <jiulongw@gmail.com> Jiulong Wang <jiulongw@gmail.com>
Joakim Sernbrant <serbaut@gmail.com> Joakim Sernbrant <serbaut@gmail.com>
Jochen Weber <jochen.weber80@gmail.com>
Joe Bowbeer <joe.bowbeer@gmail.com> Joe Bowbeer <joe.bowbeer@gmail.com>
Joe Cortopassi <joe@joecortopassi.com> Joe Cortopassi <joe@joecortopassi.com>
Joe Farrell <joe2farrell@gmail.com> Joe Farrell <joe2farrell@gmail.com>
@ -1324,6 +1382,7 @@ Johan Euphrosine <proppy@google.com>
Johan Jansson <johan.jansson@iki.fi> Johan Jansson <johan.jansson@iki.fi>
Johan Knutzen <johan@senri.se> Johan Knutzen <johan@senri.se>
Johan Sageryd <j@1616.se> Johan Sageryd <j@1616.se>
Johannes Altmanninger <aclopte@gmail.com>
Johannes Huning <johannes.huning@gmail.com> Johannes Huning <johannes.huning@gmail.com>
John Asmuth <jasmuth@gmail.com> John Asmuth <jasmuth@gmail.com>
John Bampton <jbampton@gmail.com> John Bampton <jbampton@gmail.com>
@ -1338,10 +1397,12 @@ John Howard Palevich <jack.palevich@gmail.com>
John Jago <johnjago@protonmail.com> John Jago <johnjago@protonmail.com>
John Jeffery <jjeffery@sp.com.au> John Jeffery <jjeffery@sp.com.au>
John Jenkins <twodopeshaggy@gmail.com> John Jenkins <twodopeshaggy@gmail.com>
John Kelly <jkelly@squarespace.com>
John Leidegren <john.leidegren@gmail.com> John Leidegren <john.leidegren@gmail.com>
John McCabe <john@johnmccabe.net> John McCabe <john@johnmccabe.net>
John Moore <johnkenneth.moore@gmail.com> John Moore <johnkenneth.moore@gmail.com>
John Newlin <jnewlin@google.com> John Newlin <jnewlin@google.com>
John Olheiser <john.olheiser@gmail.com>
John Papandriopoulos <jpap.code@gmail.com> John Papandriopoulos <jpap.code@gmail.com>
John Potocny <johnp@vividcortex.com> John Potocny <johnp@vividcortex.com>
John R. Lenton <jlenton@gmail.com> John R. Lenton <jlenton@gmail.com>
@ -1382,6 +1443,7 @@ Jordan Rupprecht <rupprecht@google.com>
Jordi Martin <jordimartin@gmail.com> Jordi Martin <jordimartin@gmail.com>
Jorge Araya <jorgejavieran@yahoo.com.mx> Jorge Araya <jorgejavieran@yahoo.com.mx>
Jorge L. Fatta <jorge.fatta@auth0.com> Jorge L. Fatta <jorge.fatta@auth0.com>
Jorge Troncoso <jatron@google.com>
Jos Visser <josv@google.com> Jos Visser <josv@google.com>
Josa Gesell <josa@gesell.me> Josa Gesell <josa@gesell.me>
Jose Luis Vázquez González <josvazg@gmail.com> Jose Luis Vázquez González <josvazg@gmail.com>
@ -1508,6 +1570,7 @@ Keyuan Li <keyuanli123@gmail.com>
Kezhu Wang <kezhuw@gmail.com> Kezhu Wang <kezhuw@gmail.com>
Khosrow Moossavi <khos2ow@gmail.com> Khosrow Moossavi <khos2ow@gmail.com>
Kieran Colford <kieran@kcolford.com> Kieran Colford <kieran@kcolford.com>
Kieran Gorman <kieran.j.gorman@gmail.com>
Kim Shrier <kshrier@racktopsystems.com> Kim Shrier <kshrier@racktopsystems.com>
Kim Yongbin <kybinz@gmail.com> Kim Yongbin <kybinz@gmail.com>
Kir Kolyshkin <kolyshkin@gmail.com> Kir Kolyshkin <kolyshkin@gmail.com>
@ -1577,6 +1640,7 @@ Leonel Quinteros <leonel.quinteros@gmail.com>
Lev Shamardin <shamardin@gmail.com> Lev Shamardin <shamardin@gmail.com>
Lewin Bormann <lewin.bormann@gmail.com> Lewin Bormann <lewin.bormann@gmail.com>
Lewis Waddicor <nemesismk2@gmail.com> Lewis Waddicor <nemesismk2@gmail.com>
Li-Yu Yu <aaronyu@google.com>
Liam Haworth <liam@haworth.id.au> Liam Haworth <liam@haworth.id.au>
Lily Chung <lilithkchung@gmail.com> Lily Chung <lilithkchung@gmail.com>
Lingchao Xin <douglarek@gmail.com> Lingchao Xin <douglarek@gmail.com>
@ -1657,7 +1721,9 @@ Mark Adams <mark@markadams.me>
Mark Bucciarelli <mkbucc@gmail.com> Mark Bucciarelli <mkbucc@gmail.com>
Mark Dain <mark@markdain.net> Mark Dain <mark@markdain.net>
Mark Glines <mark@glines.org> Mark Glines <mark@glines.org>
Mark Hansen <markhansen@google.com>
Mark Harrison <marhar@google.com> Mark Harrison <marhar@google.com>
Mark Jeffery <dandare100@gmail.com>
Mark Percival <m@mdp.im> Mark Percival <m@mdp.im>
Mark Pulford <mark@kyne.com.au> Mark Pulford <mark@kyne.com.au>
Mark Rushakoff <mark.rushakoff@gmail.com> Mark Rushakoff <mark.rushakoff@gmail.com>
@ -1686,7 +1752,7 @@ Martin Hoefling <martin.hoefling@gmx.de>
Martin Kreichgauer <martinkr@google.com> Martin Kreichgauer <martinkr@google.com>
Martin Kunc <martinkunc@users.noreply.github.com> Martin Kunc <martinkunc@users.noreply.github.com>
Martin Lindhe <martin.j.lindhe@gmail.com> Martin Lindhe <martin.j.lindhe@gmail.com>
Martin Möhrmann <moehrmann@google.com> <martisch@uos.de> Martin Möhrmann <martin@golang.org> <moehrmann@google.com> <martisch@uos.de>
Martin Neubauer <m.ne@gmx.net> Martin Neubauer <m.ne@gmx.net>
Martin Olsen <github.com@martinolsen.net> Martin Olsen <github.com@martinolsen.net>
Martin Olsson <martin@minimum.se> Martin Olsson <martin@minimum.se>
@ -1741,6 +1807,7 @@ Matthew Denton <mdenton@skyportsystems.com>
Matthew Holt <Matthew.Holt+git@gmail.com> Matthew Holt <Matthew.Holt+git@gmail.com>
Matthew Horsnell <matthew.horsnell@gmail.com> Matthew Horsnell <matthew.horsnell@gmail.com>
Matthew Waters <mwwaters@gmail.com> Matthew Waters <mwwaters@gmail.com>
Matthias Dötsch <matze@mdoetsch.de>
Matthias Frei <matthias.frei@inf.ethz.ch> Matthias Frei <matthias.frei@inf.ethz.ch>
Matthieu Hauglustaine <matt.hauglustaine@gmail.com> Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
Matthieu Olivier <olivier.matthieu@gmail.com> Matthieu Olivier <olivier.matthieu@gmail.com>
@ -1814,6 +1881,7 @@ Michal Bohuslávek <mbohuslavek@gmail.com>
Michal Cierniak <cierniak@google.com> Michal Cierniak <cierniak@google.com>
Michał Derkacz <ziutek@lnet.pl> Michał Derkacz <ziutek@lnet.pl>
Michal Franc <lam.michal.franc@gmail.com> Michal Franc <lam.michal.franc@gmail.com>
Michal Hruby <michal@axiom.co>
Michał Łowicki <mlowicki@gmail.com> Michał Łowicki <mlowicki@gmail.com>
Michal Pristas <michal.pristas@gmail.com> Michal Pristas <michal.pristas@gmail.com>
Michal Rostecki <mrostecki@suse.de> Michal Rostecki <mrostecki@suse.de>
@ -1844,6 +1912,7 @@ Mike Solomon <msolo@gmail.com>
Mike Strosaker <strosake@us.ibm.com> Mike Strosaker <strosake@us.ibm.com>
Mike Tsao <mike@sowbug.com> Mike Tsao <mike@sowbug.com>
Mike Wiacek <mjwiacek@google.com> Mike Wiacek <mjwiacek@google.com>
Mikhail Faraponov <11322032+moredure@users.noreply.github.com>
Mikhail Fesenko <proggga@gmail.com> Mikhail Fesenko <proggga@gmail.com>
Mikhail Gusarov <dottedmag@dottedmag.net> Mikhail Gusarov <dottedmag@dottedmag.net>
Mikhail Panchenko <m@mihasya.com> Mikhail Panchenko <m@mihasya.com>
@ -1870,6 +1939,7 @@ Moritz Fain <moritz@fain.io>
Moriyoshi Koizumi <mozo@mozo.jp> Moriyoshi Koizumi <mozo@mozo.jp>
Morten Siebuhr <sbhr@sbhr.dk> Morten Siebuhr <sbhr@sbhr.dk>
Môshe van der Sterre <moshevds@gmail.com> Môshe van der Sterre <moshevds@gmail.com>
Mostafa Solati <mostafa.solati@gmail.com>
Mostyn Bramley-Moore <mostyn@antipode.se> Mostyn Bramley-Moore <mostyn@antipode.se>
Mrunal Patel <mrunalp@gmail.com> Mrunal Patel <mrunalp@gmail.com>
Muhammad Falak R Wani <falakreyaz@gmail.com> Muhammad Falak R Wani <falakreyaz@gmail.com>
@ -1927,6 +1997,7 @@ Nick Miyake <nmiyake@users.noreply.github.com>
Nick Patavalis <nick.patavalis@gmail.com> Nick Patavalis <nick.patavalis@gmail.com>
Nick Petroni <npetroni@cs.umd.edu> Nick Petroni <npetroni@cs.umd.edu>
Nick Robinson <nrobinson13@gmail.com> Nick Robinson <nrobinson13@gmail.com>
Nick Sherron <nsherron90@gmail.com>
Nick Smolin <nick27surgut@gmail.com> Nick Smolin <nick27surgut@gmail.com>
Nicolas BRULEZ <n.brulez@gmail.com> Nicolas BRULEZ <n.brulez@gmail.com>
Nicolas Kaiser <nikai@nikai.net> Nicolas Kaiser <nikai@nikai.net>
@ -1956,6 +2027,7 @@ Noah Santschi-Cooney <noah@santschi-cooney.ch>
Noble Johnson <noblepoly@gmail.com> Noble Johnson <noblepoly@gmail.com>
Nodir Turakulov <nodir@google.com> Nodir Turakulov <nodir@google.com>
Noel Georgi <git@frezbo.com> Noel Georgi <git@frezbo.com>
Nooras Saba <saba@golang.org>
Norberto Lopes <nlopes.ml@gmail.com> Norberto Lopes <nlopes.ml@gmail.com>
Norman B. Lancaster <qbradq@gmail.com> Norman B. Lancaster <qbradq@gmail.com>
Nuno Cruces <ncruces@users.noreply.github.com> Nuno Cruces <ncruces@users.noreply.github.com>
@ -1973,6 +2045,7 @@ Oliver Tan <otan@cockroachlabs.com>
Oliver Tonnhofer <olt@bogosoft.com> Oliver Tonnhofer <olt@bogosoft.com>
Olivier Antoine <olivier.antoine@gmail.com> Olivier Antoine <olivier.antoine@gmail.com>
Olivier Duperray <duperray.olivier@gmail.com> Olivier Duperray <duperray.olivier@gmail.com>
Olivier Mengué <olivier.mengue@gmail.com>
Olivier Poitrey <rs@dailymotion.com> Olivier Poitrey <rs@dailymotion.com>
Olivier Saingre <osaingre@gmail.com> Olivier Saingre <osaingre@gmail.com>
Olivier Wulveryck <olivier.wulveryck@gmail.com> Olivier Wulveryck <olivier.wulveryck@gmail.com>
@ -1982,6 +2055,7 @@ Ori Bernstein <ori@eigenstate.org>
Ori Rawlings <orirawlings@gmail.com> Ori Rawlings <orirawlings@gmail.com>
Oryan Moshe <iamoryanmoshe@gmail.com> Oryan Moshe <iamoryanmoshe@gmail.com>
Osamu TONOMORI <osamingo@gmail.com> Osamu TONOMORI <osamingo@gmail.com>
Oscar Söderlund <oscar.soderlund@einride.tech>
Özgür Kesim <oec-go@kesim.org> Özgür Kesim <oec-go@kesim.org>
Pablo Caderno <kaderno@gmail.com> Pablo Caderno <kaderno@gmail.com>
Pablo Lalloni <plalloni@gmail.com> Pablo Lalloni <plalloni@gmail.com>
@ -2014,6 +2088,7 @@ Patrick Pelletier <pp.pelletier@gmail.com>
Patrick Riley <pfr@google.com> Patrick Riley <pfr@google.com>
Patrick Smith <pat42smith@gmail.com> Patrick Smith <pat42smith@gmail.com>
Patrik Lundin <patrik@sigterm.se> Patrik Lundin <patrik@sigterm.se>
Patrik Nyblom <pnyb@google.com>
Paul A Querna <paul.querna@gmail.com> Paul A Querna <paul.querna@gmail.com>
Paul Borman <borman@google.com> Paul Borman <borman@google.com>
Paul Boyd <boyd.paul2@gmail.com> Paul Boyd <boyd.paul2@gmail.com>
@ -2042,6 +2117,7 @@ Paul Wankadia <junyer@google.com>
Paulo Casaretto <pcasaretto@gmail.com> Paulo Casaretto <pcasaretto@gmail.com>
Paulo Flabiano Smorigo <pfsmorigo@linux.vnet.ibm.com> Paulo Flabiano Smorigo <pfsmorigo@linux.vnet.ibm.com>
Paulo Gomes <paulo.gomes.uk@gmail.com> Paulo Gomes <paulo.gomes.uk@gmail.com>
Pavel Kositsyn <kositsyn.pa@phystech.edu>
Pavel Paulau <pavel.paulau@gmail.com> Pavel Paulau <pavel.paulau@gmail.com>
Pavel Watson <watsonpavel@gmail.com> Pavel Watson <watsonpavel@gmail.com>
Pavel Zinovkin <pavel.zinovkin@gmail.com> Pavel Zinovkin <pavel.zinovkin@gmail.com>
@ -2049,6 +2125,7 @@ Pavlo Sumkin <ymkins@gmail.com>
Pawel Knap <pawelknap88@gmail.com> Pawel Knap <pawelknap88@gmail.com>
Pawel Szczur <filemon@google.com> Pawel Szczur <filemon@google.com>
Paweł Szulik <pawel.szulik@intel.com> Paweł Szulik <pawel.szulik@intel.com>
Pedro Lopez Mareque <pedro.lopez.mareque@gmail.com>
Pei Xian Chee <luciolas1991@gmail.com> Pei Xian Chee <luciolas1991@gmail.com>
Pei-Ming Wu <p408865@gmail.com> Pei-Ming Wu <p408865@gmail.com>
Pen Tree <appletree2479@outlook.com> Pen Tree <appletree2479@outlook.com>
@ -2164,6 +2241,7 @@ Rhys Hiltner <rhys@justin.tv>
Ricardo Padilha <ricardospadilha@gmail.com> Ricardo Padilha <ricardospadilha@gmail.com>
Ricardo Pchevuzinske Katz <ricardo.katz@serpro.gov.br> Ricardo Pchevuzinske Katz <ricardo.katz@serpro.gov.br>
Ricardo Seriani <ricardo.seriani@gmail.com> Ricardo Seriani <ricardo.seriani@gmail.com>
Rich Hong <hong.rich@gmail.com>
Richard Barnes <rlb@ipv.sx> Richard Barnes <rlb@ipv.sx>
Richard Crowley <r@rcrowley.org> Richard Crowley <r@rcrowley.org>
Richard Dingwall <rdingwall@gmail.com> Richard Dingwall <rdingwall@gmail.com>
@ -2179,6 +2257,7 @@ Rick Hudson <rlh@golang.org>
Rick Sayre <whorfin@gmail.com> Rick Sayre <whorfin@gmail.com>
Rijnard van Tonder <rvantonder@gmail.com> Rijnard van Tonder <rvantonder@gmail.com>
Riku Voipio <riku.voipio@linaro.org> Riku Voipio <riku.voipio@linaro.org>
Riley Avron <ra.git@posteo.net>
Risto Jaakko Saarelma <rsaarelm@gmail.com> Risto Jaakko Saarelma <rsaarelm@gmail.com>
Rob Earhart <earhart@google.com> Rob Earhart <earhart@google.com>
Rob Findley <rfindley@google.com> Rob Findley <rfindley@google.com>
@ -2186,8 +2265,10 @@ Rob Norman <rob.norman@infinitycloud.com>
Rob Phoenix <rob@robphoenix.com> Rob Phoenix <rob@robphoenix.com>
Rob Pike <r@golang.org> Rob Pike <r@golang.org>
Robert Ayrapetyan <robert.ayrapetyan@gmail.com> Robert Ayrapetyan <robert.ayrapetyan@gmail.com>
Robert Burke <rebo@google.com>
Robert Daniel Kortschak <dan.kortschak@adelaide.edu.au> <dan@kortschak.io> Robert Daniel Kortschak <dan.kortschak@adelaide.edu.au> <dan@kortschak.io>
Robert Dinu <r@varp.se> Robert Dinu <r@varp.se>
Robert Engels <rengels@ix.netcom.com>
Robert Figueiredo <robfig@gmail.com> Robert Figueiredo <robfig@gmail.com>
Robert Griesemer <gri@golang.org> Robert Griesemer <gri@golang.org>
Robert Hencke <robert.hencke@gmail.com> Robert Hencke <robert.hencke@gmail.com>
@ -2212,6 +2293,7 @@ Roger Peppe <rogpeppe@gmail.com>
Rohan Challa <rohan@golang.org> Rohan Challa <rohan@golang.org>
Rohan Verma <rohanverma2004@gmail.com> Rohan Verma <rohanverma2004@gmail.com>
Rohith Ravi <entombedvirus@gmail.com> Rohith Ravi <entombedvirus@gmail.com>
Roi Martin <jroi.martin@gmail.com>
Roland Illig <roland.illig@gmx.de> Roland Illig <roland.illig@gmx.de>
Roland Shoemaker <rolandshoemaker@gmail.com> Roland Shoemaker <rolandshoemaker@gmail.com>
Romain Baugue <romain.baugue@elwinar.com> Romain Baugue <romain.baugue@elwinar.com>
@ -2242,6 +2324,7 @@ Ryan Canty <jrcanty@gmail.com>
Ryan Dahl <ry@tinyclouds.org> Ryan Dahl <ry@tinyclouds.org>
Ryan Hitchman <hitchmanr@gmail.com> Ryan Hitchman <hitchmanr@gmail.com>
Ryan Kohler <ryankohler@google.com> Ryan Kohler <ryankohler@google.com>
Ryan Leung <rleungx@gmail.com>
Ryan Lower <rpjlower@gmail.com> Ryan Lower <rpjlower@gmail.com>
Ryan Roden-Corrent <ryan@rcorre.net> Ryan Roden-Corrent <ryan@rcorre.net>
Ryan Seys <ryan@ryanseys.com> Ryan Seys <ryan@ryanseys.com>
@ -2275,6 +2358,7 @@ Sami Pönkänen <sami.ponkanen@gmail.com>
Samuel Kelemen <SCKelemen@users.noreply.github.com> Samuel Kelemen <SCKelemen@users.noreply.github.com>
Samuel Tan <samueltan@google.com> Samuel Tan <samueltan@google.com>
Samuele Pedroni <pedronis@lucediurna.net> Samuele Pedroni <pedronis@lucediurna.net>
San Ye <xyesan@gmail.com>
Sander van Harmelen <sander@vanharmelen.nl> Sander van Harmelen <sander@vanharmelen.nl>
Sanjay Menakuru <balasanjay@gmail.com> Sanjay Menakuru <balasanjay@gmail.com>
Santhosh Kumar Tekuri <santhosh.tekuri@gmail.com> Santhosh Kumar Tekuri <santhosh.tekuri@gmail.com>
@ -2339,6 +2423,7 @@ Shaba Abhiram <shabarivas.abhiram@gmail.com>
Shahar Kohanim <skohanim@gmail.com> Shahar Kohanim <skohanim@gmail.com>
Shailesh Suryawanshi <ss.shailesh28@gmail.com> Shailesh Suryawanshi <ss.shailesh28@gmail.com>
Shamil Garatuev <garatuev@gmail.com> Shamil Garatuev <garatuev@gmail.com>
Shamim Akhtar <shamim.rhce@gmail.com>
Shane Hansen <shanemhansen@gmail.com> Shane Hansen <shanemhansen@gmail.com>
Shang Jian Ding <sding3@ncsu.edu> Shang Jian Ding <sding3@ncsu.edu>
Shaozhen Ding <dsz0111@gmail.com> Shaozhen Ding <dsz0111@gmail.com>
@ -2375,6 +2460,7 @@ Simon Drake <simondrake1990@gmail.com>
Simon Ferquel <simon.ferquel@docker.com> Simon Ferquel <simon.ferquel@docker.com>
Simon Frei <freisim93@gmail.com> Simon Frei <freisim93@gmail.com>
Simon Jefford <simon.jefford@gmail.com> Simon Jefford <simon.jefford@gmail.com>
Simon Law <sfllaw@sfllaw.ca>
Simon Rawet <simon@rawet.se> Simon Rawet <simon@rawet.se>
Simon Rozman <simon@rozman.si> Simon Rozman <simon@rozman.si>
Simon Ser <contact@emersion.fr> Simon Ser <contact@emersion.fr>
@ -2440,6 +2526,7 @@ Suharsh Sivakumar <suharshs@google.com>
Sukrit Handa <sukrit.handa@utoronto.ca> Sukrit Handa <sukrit.handa@utoronto.ca>
Sunny <me@darkowlzz.space> Sunny <me@darkowlzz.space>
Suriyaa Sundararuban <suriyaasundararuban@gmail.com> Suriyaa Sundararuban <suriyaasundararuban@gmail.com>
Suvaditya Sur <suvaditya.sur@gmail.com>
Suyash <dextrous93@gmail.com> Suyash <dextrous93@gmail.com>
Suzy Mueller <suzmue@golang.org> Suzy Mueller <suzmue@golang.org>
Sven Almgren <sven@tras.se> Sven Almgren <sven@tras.se>
@ -2502,6 +2589,7 @@ Thomas Symborski <thomas.symborski@gmail.com>
Thomas Wanielista <tomwans@gmail.com> Thomas Wanielista <tomwans@gmail.com>
Thorben Krueger <thorben.krueger@gmail.com> Thorben Krueger <thorben.krueger@gmail.com>
Thordur Bjornsson <thorduri@secnorth.net> Thordur Bjornsson <thorduri@secnorth.net>
Tiago Peczenyj <tpeczenyj@weborama.com>
Tiago Queiroz <contato@tiago.eti.br> Tiago Queiroz <contato@tiago.eti.br>
Tianji Wu <the729@gmail.com> Tianji Wu <the729@gmail.com>
Tianon Gravi <admwiggin@gmail.com> Tianon Gravi <admwiggin@gmail.com>
@ -2636,6 +2724,7 @@ Vladimir Varankin <nek.narqo@gmail.com>
Vojtech Bocek <vbocek@gmail.com> Vojtech Bocek <vbocek@gmail.com>
Volker Dobler <dr.volker.dobler@gmail.com> Volker Dobler <dr.volker.dobler@gmail.com>
Volodymyr Paprotski <vpaprots@ca.ibm.com> Volodymyr Paprotski <vpaprots@ca.ibm.com>
Vyacheslav Pachkov <slava.pach@gmail.com>
W. Trevor King <wking@tremily.us> W. Trevor King <wking@tremily.us>
Wade Simmons <wade@wades.im> Wade Simmons <wade@wades.im>
Wagner Riffel <wgrriffel@gmail.com> Wagner Riffel <wgrriffel@gmail.com>
@ -2653,6 +2742,7 @@ Wei Guangjing <vcc.163@gmail.com>
Wei Xiao <wei.xiao@arm.com> Wei Xiao <wei.xiao@arm.com>
Wei Xikai <xykwei@gmail.com> Wei Xikai <xykwei@gmail.com>
Weichao Tang <tevic.tt@gmail.com> Weichao Tang <tevic.tt@gmail.com>
Weilu Jia <optix2000@gmail.com>
Weixie Cui <cuiweixie@gmail.com> <523516579@qq.com> Weixie Cui <cuiweixie@gmail.com> <523516579@qq.com>
Wembley G. Leach, Jr <wembley.gl@gmail.com> Wembley G. Leach, Jr <wembley.gl@gmail.com>
Wenlei (Frank) He <wlhe@google.com> Wenlei (Frank) He <wlhe@google.com>
@ -2722,9 +2812,11 @@ Yuichi Nishiwaki <yuichi.nishiwaki@gmail.com>
Yuji Yaginuma <yuuji.yaginuma@gmail.com> Yuji Yaginuma <yuuji.yaginuma@gmail.com>
Yuki Ito <mrno110y@gmail.com> Yuki Ito <mrno110y@gmail.com>
Yuki OKUSHI <huyuumi.dev@gmail.com> Yuki OKUSHI <huyuumi.dev@gmail.com>
Yuki Osaki <yuki.osaki7@gmail.com>
Yuki Yugui Sonoda <yugui@google.com> Yuki Yugui Sonoda <yugui@google.com>
Yukihiro Nishinaka <6elpinal@gmail.com> Yukihiro Nishinaka <6elpinal@gmail.com>
YunQiang Su <syq@debian.org> YunQiang Su <syq@debian.org>
Yuntao Wang <ytcoode@gmail.com>
Yury Smolsky <yury@smolsky.by> Yury Smolsky <yury@smolsky.by>
Yusuke Kagiwada <block.rxckin.beats@gmail.com> Yusuke Kagiwada <block.rxckin.beats@gmail.com>
Yuusei Kuwana <kuwana@kumama.org> Yuusei Kuwana <kuwana@kumama.org>
@ -2736,7 +2828,9 @@ Zach Gershman <zachgersh@gmail.com>
Zach Hoffman <zrhoffman@apache.org> Zach Hoffman <zrhoffman@apache.org>
Zach Jones <zachj1@gmail.com> Zach Jones <zachj1@gmail.com>
Zachary Amsden <zach@thundertoken.com> Zachary Amsden <zach@thundertoken.com>
Zachary Burkett <zburkett@splitcubestudios.com>
Zachary Gershman <zgershman@pivotal.io> Zachary Gershman <zgershman@pivotal.io>
Zaiyang Li <zaiyangli777@gmail.com>
Zak <zrjknill@gmail.com> Zak <zrjknill@gmail.com>
Zakatell Kanda <hi@zkanda.io> Zakatell Kanda <hi@zkanda.io>
Zellyn Hunter <zellyn@squareup.com> <zellyn@gmail.com> Zellyn Hunter <zellyn@squareup.com> <zellyn@gmail.com>
@ -2745,6 +2839,7 @@ Zhang Boyang <zhangboyang.id@gmail.com>
Zheng Dayu <davidzheng23@gmail.com> Zheng Dayu <davidzheng23@gmail.com>
Zheng Xu <zheng.xu@arm.com> Zheng Xu <zheng.xu@arm.com>
Zhengyu He <hzy@google.com> Zhengyu He <hzy@google.com>
Zhi Zheng <zhi.zheng052@gmail.com>
Zhongpeng Lin <zplin@uber.com> Zhongpeng Lin <zplin@uber.com>
Zhongtao Chen <chenzhongtao@126.com> Zhongtao Chen <chenzhongtao@126.com>
Zhongwei Yao <zhongwei.yao@arm.com> Zhongwei Yao <zhongwei.yao@arm.com>

View File

@ -165,8 +165,8 @@ pkg reflect, method (Value) FieldByIndexErr([]int) (Value, error)
pkg reflect, method (Value) SetIterKey(*MapIter) pkg reflect, method (Value) SetIterKey(*MapIter)
pkg reflect, method (Value) SetIterValue(*MapIter) pkg reflect, method (Value) SetIterValue(*MapIter)
pkg reflect, method (Value) UnsafePointer() unsafe.Pointer pkg reflect, method (Value) UnsafePointer() unsafe.Pointer
pkg runtime/debug, method (*BuildInfo) MarshalText() ([]uint8, error) pkg runtime/debug, func ParseBuildInfo(string) (*BuildInfo, error)
pkg runtime/debug, method (*BuildInfo) UnmarshalText([]uint8) error pkg runtime/debug, method (*BuildInfo) String() string
pkg runtime/debug, type BuildInfo struct, GoVersion string pkg runtime/debug, type BuildInfo struct, GoVersion string
pkg runtime/debug, type BuildInfo struct, Settings []BuildSetting pkg runtime/debug, type BuildInfo struct, Settings []BuildSetting
pkg runtime/debug, type BuildSetting struct pkg runtime/debug, type BuildSetting struct

View File

@ -1,2 +1,2 @@
branch: dev.boringcrypto branch: dev.boringcrypto.go1.18
parent-branch: master parent-branch: master

View File

@ -84,7 +84,7 @@ Do not send CLs removing the interior tags from such phrases.
<li> <li>
The new The new
<a href="/ref/spec#Predeclared_identifiers">predeclared identifier</a> <a href="/ref/spec#Predeclared_identifiers">predeclared identifier</a>
<code>comparable</code> is an interface the denotes the set of all types which can be <code>comparable</code> is an interface that denotes the set of all types which can be
compared using <code>==</code> or <code>!=</code>. It may only be used as (or embedded in) compared using <code>==</code> or <code>!=</code>. It may only be used as (or embedded in)
a type constraint. a type constraint.
</li> </li>
@ -135,9 +135,19 @@ Do not send CLs removing the interior tags from such phrases.
the predeclared functions <code>real</code>, <code>imag</code>, and <code>complex</code>. the predeclared functions <code>real</code>, <code>imag</code>, and <code>complex</code>.
We hope to remove this restriction in Go 1.19. We hope to remove this restriction in Go 1.19.
</li> </li>
<li><!-- https://golang.org/issue/51183 -->
The Go compiler currently only supports calling a method <code>m</code> on a value
<code>x</code> of type parameter type <code>P</code> if <code>m</code> is explicitly
declared by <code>P</code>'s constraint interface.
Similarly, method values <code>x.m</code> and method expressions
<code>P.m</code> also are only supported if <code>m</code> is explicitly
declared by <code>P</code>, even though <code>m</code> might be in the method set
of <code>P</code> by virtue of the fact that all types in <code>P</code> implement
<code>m</code>. We hope to remove this restriction in Go 1.19.
</li>
<li><!-- https://golang.org/issue/49030 --> <li><!-- https://golang.org/issue/49030 -->
Embedding a type parameter, or a pointer to a type parameter, as 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. embedding a type parameter in an interface type is not permitted.
Whether these will ever be permitted is unclear at present. Whether these will ever be permitted is unclear at present.
</li> </li>
@ -182,7 +192,7 @@ Do not send CLs removing the interior tags from such phrases.
<p><!-- CL 349595 --> <p><!-- CL 349595 -->
Go 1.18 introduces the new <code>GOAMD64</code> environment variable, which selects at compile time Go 1.18 introduces the new <code>GOAMD64</code> environment variable, which selects at compile time
a mininum target version of the AMD64 architecture. Allowed values are <code>v1</code>, a minimum target version of the AMD64 architecture. Allowed values are <code>v1</code>,
<code>v2</code>, <code>v3</code>, or <code>v4</code>. Each higher level requires, <code>v2</code>, <code>v3</code>, or <code>v4</code>. Each higher level requires,
and takes advantage of, additional processor features. A detailed and takes advantage of, additional processor features. A detailed
description can be found description can be found
@ -199,6 +209,12 @@ Do not send CLs removing the interior tags from such phrases.
now supports the <code>c-archive</code> and <code>c-shared</code> build modes. now supports the <code>c-archive</code> and <code>c-shared</code> build modes.
</p> </p>
<h3 id="linux">Linux</h3>
<p><!-- golang.org/issue/45964 -->
Go 1.18 requires Linux kernel version 2.6.32 or later.
</p>
<h3 id="windows">Windows</h3> <h3 id="windows">Windows</h3>
<p><!-- https://golang.org/issue/49759 --> <p><!-- https://golang.org/issue/49759 -->
@ -250,6 +266,8 @@ Do not send CLs removing the interior tags from such phrases.
<h3 id="go-command">Go command</h3> <h3 id="go-command">Go command</h3>
<h4 id="go-get"><code>go</code> <code>get</code></h4>
<p><!-- golang.org/issue/43684 --> <p><!-- golang.org/issue/43684 -->
<code>go</code> <code>get</code> no longer builds or installs packages in <code>go</code> <code>get</code> no longer builds or installs packages in
module-aware mode. <code>go</code> <code>get</code> is now dedicated to module-aware mode. <code>go</code> <code>get</code> is now dedicated to
@ -269,9 +287,25 @@ Do not send CLs removing the interior tags from such phrases.
and installs packages, as before. and installs packages, as before.
</p> </p>
<h4 id="go-mod-updates">Automatic <code>go.mod</code> and <code>go.sum</code> updates</h4>
<p><!-- https://go.dev/issue/45551 -->
The <code>go</code> <code>mod</code> <code>graph</code>,
<code>go</code> <code>mod</code> <code>vendor</code>,
<code>go</code> <code>mod</code> <code>verify</code>, and
<code>go</code> <code>mod</code> <code>why</code> subcommands
no longer automatically update the <code>go.mod</code> and
<code>go.sum</code> files.
(Those files can be updated explicitly using <code>go</code> <code>get</code>,
<code>go</code> <code>mod</code> <code>tidy</code>, or
<code>go</code> <code>mod</code> <code>download</code>.)
</p>
<h4 id="go-version"><code>go</code> <code>version</code></h4>
<p><!-- golang.org/issue/37475 --> <p><!-- golang.org/issue/37475 -->
The <code>go</code> command now embeds version control information in The <code>go</code> 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 flag indicating whether edited or untracked files are present. Version
control information is embedded if the <code>go</code> command is invoked in control information is embedded if the <code>go</code> command is invoked in
a directory within a Git, Mercurial, Fossil, or Bazaar repository, and the 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.
</p> </p>
<p><!-- golang.org/issue/37475 --> <p><!-- golang.org/issue/37475 -->
Additionally, the <code>go</code> command embeds information about the build Additionally, the <code>go</code> command embeds information about the build,
including build and tool tags (set with <code>-tags</code>), compiler, including build and tool tags (set with <code>-tags</code>), compiler,
assembler, and linker flags (like <code>-gcflags</code>), whether cgo was assembler, and linker flags (like <code>-gcflags</code>), whether cgo was
enabled, and if it was, the values of the cgo environment variables 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.
<code>debug/buildinfo</code> package from <code>go</code> 1.18+. <code>debug/buildinfo</code> package from <code>go</code> 1.18+.
</p> </p>
<h4 id="go-mod-download"><code>go</code> <code>mod</code> <code>download</code></h4>
<p><!-- https://golang.org/issue/44435 --> <p><!-- https://golang.org/issue/44435 -->
If the main module's <code>go.mod</code> file If the main module's <code>go.mod</code> file
specifies <a href="/ref/mod#go-mod-file-go"><code>go</code> <code>1.17</code></a> specifies <a href="/ref/mod#go-mod-file-go"><code>go</code> <code>1.17</code></a>
@ -316,6 +352,8 @@ Do not send CLs removing the interior tags from such phrases.
<code>go</code> <code>mod</code> <code>download</code> <code>all</code>. <code>go</code> <code>mod</code> <code>download</code> <code>all</code>.
</p> </p>
<h4 id="go-mod-vendor"><code>go</code> <code>mod</code> <code>vendor</code></h4>
<p><!-- https://golang.org/issue/47327 --> <p><!-- https://golang.org/issue/47327 -->
The <code>go</code> <code>mod</code> <code>vendor</code> subcommand now The <code>go</code> <code>mod</code> <code>vendor</code> subcommand now
supports a <code>-o</code> flag to set the output directory. supports a <code>-o</code> flag to set the output directory.
@ -325,14 +363,9 @@ Do not send CLs removing the interior tags from such phrases.
third-party tools that need to collect package source code.) third-party tools that need to collect package source code.)
</p> </p>
<p><!-- CL 298612 --> <h4 id="go-mod-tidy"><code>go</code> <code>mod</code> <code>tidy</code></h4>
The <code>go</code> <code>build</code> command and related commands
now support an <code>-asan</code> flag that enables interoperation
with C (or C++) code compiled with the address sanitizer (C compiler
option <code>-fsanitize=address</code>).
</p>
<p><!-- https://golang.org/issue/47738 --> <p><!-- https://golang.org/issue/47738, CL 344572 -->
The <code>go</code> <code>mod</code> <code>tidy</code> command now retains The <code>go</code> <code>mod</code> <code>tidy</code> command now retains
additional checksums in the <code>go.sum</code> file for modules whose source additional checksums in the <code>go.sum</code> file for modules whose source
code is needed to verify that each imported package is provided by only one code is needed to verify that each imported package is provided by only one
@ -342,11 +375,13 @@ Do not send CLs removing the interior tags from such phrases.
module's <code>go.mod</code> file. module's <code>go.mod</code> file.
</p> </p>
<h4 id="go-work"><code>go</code> <code>work</code></h4>
<p><!-- https://golang.org/issue/45713 --> <p><!-- https://golang.org/issue/45713 -->
The <code>go</code> command now supports a "Workspace" mode. If a The <code>go</code> command now supports a "Workspace" mode. If a
<code>go.work</code> file is found in the working directory or a <code>go.work</code> file is found in the working directory or a
parent directory, or one is specified using the <code>-workfile</code> parent directory, or one is specified using the <code>GOWORK</code>
flag, it will put the <code>go</code> command into workspace mode. environment variable, it will put the <code>go</code> command into workspace mode.
In workspace mode, the <code>go.work</code> file will be used to In workspace mode, the <code>go.work</code> file will be used to
determine the set of main modules used as the roots for module determine the set of main modules used as the roots for module
resolution, instead of using the normally-found <code>go.mod</code> resolution, instead of using the normally-found <code>go.mod</code>
@ -355,6 +390,17 @@ Do not send CLs removing the interior tags from such phrases.
documentation. documentation.
</p> </p>
<h4 id="go-build-asan"><code>go</code> <code>build</code> <code>-asan</code></h4>
<p><!-- CL 298612 -->
The <code>go</code> <code>build</code> command and related commands
now support an <code>-asan</code> flag that enables interoperation
with C (or C++) code compiled with the address sanitizer (C compiler
option <code>-fsanitize=address</code>).
</p>
<h4 id="go-test"><code>go</code> <code>test</code></h4>
<p><!-- CL 251441 --> <p><!-- CL 251441 -->
The <code>go</code> command now supports additional command line The <code>go</code> command now supports additional command line
options for the new <a href="#fuzzing">fuzzing support described options for the new <a href="#fuzzing">fuzzing support described
@ -376,7 +422,28 @@ Do not send CLs removing the interior tags from such phrases.
</ul> </ul>
</p> </p>
<h3 id="gofmt"><code>gofmt</code></h3> <h4 id="go-build-lines"><code>//go:build</code> lines</h4>
<p><!-- CL 240611 -->
Go 1.17 introduced <code>//go:build</code> lines as a more readable way to write build constraints,
instead of <code>//</code> <code>+build</code> lines.
As of Go 1.17, <code>gofmt</code> adds <code>//go:build</code> lines
to match existing <code>+build</code> lines and keeps them in sync,
while <code>go</code> <code>vet</code> diagnoses when they are out of sync.
</p>
<p>Since the release of Go 1.18 marks the end of support for Go 1.16,
all supported versions of Go now understand <code>//go:build</code> lines.
In Go 1.18, <code>go</code> <code>fix</code> now removes the now-obsolete
<code>//</code> <code>+build</code> lines in modules declaring
<code>go</code> <code>1.17</code> or later in their <code>go.mod</code> files.
</p>
<p>
For more information, see <a href="https://go.dev/design/draft-gobuild">https://go.dev/design/draft-gobuild</a>.
</p>
<h3 id="gofmt">Gofmt</h3>
<p><!-- https://golang.org/issue/43566 --> <p><!-- https://golang.org/issue/43566 -->
<code>gofmt</code> now reads and formats input files concurrently, with a <code>gofmt</code> now reads and formats input files concurrently, with a
@ -384,7 +451,7 @@ Do not send CLs removing the interior tags from such phrases.
multiple CPUs, <code>gofmt</code> should now be significantly faster. multiple CPUs, <code>gofmt</code> should now be significantly faster.
</p> </p>
<h3 id="vet"><code>vet</code></h3> <h3 id="vet">Vet</h3>
<h4 id="vet-generics">Updates for Generics</h4> <h4 id="vet-generics">Updates for Generics</h4>
@ -472,7 +539,7 @@ Do not send CLs removing the interior tags from such phrases.
</p> </p>
<p><!-- CL 298611 --> <p><!-- CL 298611 -->
The new compiler <code>-asan</code> option supports the The new <code>-asan</code> compiler option supports the
new <code>go</code> command <code>-asan</code> option. new <code>go</code> command <code>-asan</code> option.
</p> </p>
@ -502,10 +569,23 @@ Do not send CLs removing the interior tags from such phrases.
</p> </p>
<p><!-- CL 298610 --> <p><!-- CL 298610 -->
The new linker <code>-asan</code> option supports the The new <code>-asan</code> linker option supports the
new <code>go</code> command <code>-asan</code> option. new <code>go</code> command <code>-asan</code> option.
</p> </p>
<h2 id="bootstrap">Bootstrap</h2>
<p><!-- CL 369914, CL 370274 -->
When building a Go release from source and <code>GOROOT_BOOTSTRAP</code>
is not set, previous versions of Go looked for a Go 1.4 or later bootstrap toolchain
in the directory <code>$HOME/go1.4</code> (<code>%HOMEDRIVE%%HOMEPATH%\go1.4</code> on Windows).
Go now looks first for <code>$HOME/go1.17</code> or <code>$HOME/sdk/go1.17</code>
before falling back to <code>$HOME/go1.4</code>.
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 <a href="https://go.dev/issue/44505">go.dev/issue/44505</a>.
</p>
<h2 id="library">Core library</h2> <h2 id="library">Core library</h2>
<h3 id="debug/buildinfo">New <code>debug/buildinfo</code> package</h3> <h3 id="debug/buildinfo">New <code>debug/buildinfo</code> package</h3>
@ -630,8 +710,8 @@ Do not send CLs removing the interior tags from such phrases.
</p> </p>
<p><!-- CL 345570 --> <p><!-- CL 345570 -->
The methods <a href="/pkg/bufio#Reader.Reset"><code>Reader.Reset</code></a> and The <a href="/pkg/bufio#Reader.Reset"><code>Reader.Reset</code></a> and
<a href="/pkg/bufio#Writer.Reset"><code>Writer.Reset</code></a> <a href="/pkg/bufio#Writer.Reset"><code>Writer.Reset</code></a> methods
now use the default buffer size when called on objects with a now use the default buffer size when called on objects with a
<code>nil</code> buffer. <code>nil</code> buffer.
</p> </p>
@ -909,6 +989,19 @@ Do not send CLs removing the interior tags from such phrases.
field. field.
</li> </li>
</ul> </ul>
<p>
The predicates
<a href="/pkg/go/types/#AssignableTo"><code>AssignableTo</code></a>,
<a href="/pkg/go/types/#ConvertibleTo"><code>ConvertibleTo</code></a>,
<a href="/pkg/go/types/#Implements"><code>Implements</code></a>,
<a href="/pkg/go/types/#Identical"><code>Identical</code></a>,
<a href="/pkg/go/types/#IdenticalIgnoreTags"><code>IdenticalIgnoreTags</code></a>, and
<a href="/pkg/go/types/#AssertableTo"><code>AssertableTo</code></a>
now also work with arguments that are or contain generalized interfaces, i.e. interfaces
that may only be used as type constraints in Go code.
Note that the behavior of <code>AssertableTo</code> is undefined if the first argument
is a generalized interface.
</p>
</dd> </dd>
</dl> </dl>
@ -980,7 +1073,7 @@ Do not send CLs removing the interior tags from such phrases.
<dl id="os/user"><dt><a href="/pkg/os/user/">os/user</a></dt> <dl id="os/user"><dt><a href="/pkg/os/user/">os/user</a></dt>
<dd> <dd>
<p><!-- CL 330753 --> <p><!-- CL 330753 -->
<a href="/pkg/os/user#User.GroupIds"><code>User.GroupIds</code></a>. <a href="/pkg/os/user#User.GroupIds"><code>User.GroupIds</code></a>
now uses a Go native implementation when cgo is not available. now uses a Go native implementation when cgo is not available.
</p> </p>
</dd> </dd>
@ -993,7 +1086,7 @@ Do not send CLs removing the interior tags from such phrases.
<a href="/pkg/reflect/#Value.SetIterKey"><code>Value.SetIterKey</code></a> <a href="/pkg/reflect/#Value.SetIterKey"><code>Value.SetIterKey</code></a>
and <a href="/pkg/reflect/#Value.SetIterValue"><code>Value.SetIterValue</code></a> and <a href="/pkg/reflect/#Value.SetIterValue"><code>Value.SetIterValue</code></a>
methods set a Value using a map iterator as the source. They are equivalent to methods set a Value using a map iterator as the source. They are equivalent to
<code>Value.Set(iter.Key())</code> and <code>Value.Set(iter.Value())</code> but <code>Value.Set(iter.Key())</code> and <code>Value.Set(iter.Value())</code>, but
do fewer allocations. do fewer allocations.
</p> </p>
@ -1045,7 +1138,7 @@ Do not send CLs removing the interior tags from such phrases.
The old names will continue to work, but will be deprecated in a The old names will continue to work, but will be deprecated in a
future Go release. future Go release.
</p> </p>
</dd> </dd><!-- CL 321889 and CL 345486 are optimizations, no need to mention. -->
</dl><!-- reflect --> </dl><!-- reflect -->
<dl id="regexp"><dt><a href="/pkg/regexp/">regexp</a></dt> <dl id="regexp"><dt><a href="/pkg/regexp/">regexp</a></dt>
@ -1078,6 +1171,16 @@ Do not send CLs removing the interior tags from such phrases.
</dd> </dd>
</dl><!-- runtime/debug --> </dl><!-- runtime/debug -->
<dl id="runtime/pprof"><dt><a href="/pkg/runtime/pprof/">runtime/pprof</a></dt>
<dd>
<p><!-- CL 324129 -->
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.
</p>
</dd>
</dl><!-- runtime/pprof -->
<dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt> <dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
<dd> <dd>
<p><!-- CL 343877 --> <p><!-- CL 343877 -->
@ -1147,7 +1250,7 @@ Do not send CLs removing the interior tags from such phrases.
</p> </p>
<p><!-- CL 355570 --> <p><!-- CL 355570 -->
<a href="/pkg/syscall/?GOOS=freebsd#SysProcAttr.Pdeathsig"><code>SysProcAttr.Pdeathsig</code></a>. <a href="/pkg/syscall/?GOOS=freebsd#SysProcAttr.Pdeathsig"><code>SysProcAttr.Pdeathsig</code></a>
is now supported in FreeBSD. is now supported in FreeBSD.
</p> </p>
</dd> </dd>
@ -1156,7 +1259,7 @@ Do not send CLs removing the interior tags from such phrases.
<dl id="syscall/js"><dt><a href="/pkg/syscall/js/">syscall/js</a></dt> <dl id="syscall/js"><dt><a href="/pkg/syscall/js/">syscall/js</a></dt>
<dd> <dd>
<p><!-- CL 356430 --> <p><!-- CL 356430 -->
<code>Wrapper</code> interface has been removed. The <code>Wrapper</code> interface has been removed.
</p> </p>
</dd> </dd>
</dl><!-- syscall/js --> </dl><!-- syscall/js -->
@ -1228,7 +1331,7 @@ Do not send CLs removing the interior tags from such phrases.
<dl id="unicode/utf8"><dt><a href="/pkg/unicode/utf8/">unicode/utf8</a></dt> <dl id="unicode/utf8"><dt><a href="/pkg/unicode/utf8/">unicode/utf8</a></dt>
<dd> <dd>
<p><!-- CL 345571 --> <p><!-- CL 345571 -->
The <a href="/pkg/unicode/utf8/#AppendRune"><code>AppendRune</code></a> function appends the UTF-8 new The new <a href="/pkg/unicode/utf8/#AppendRune"><code>AppendRune</code></a> function appends the UTF-8
encoding of a <code>rune</code> to a <code>[]byte</code>. encoding of a <code>rune</code> to a <code>[]byte</code>.
</p> </p>
</dd> </dd>

File diff suppressed because it is too large Load Diff

View File

@ -63,7 +63,7 @@ func TestASAN(t *testing.T) {
// sanitizer library needs a // sanitizer library needs a
// symbolizer program and can't find it. // symbolizer program and can't find it.
const noSymbolizer = "external symbolizer" 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 != "" && if tc.errorLocation != "" &&
!strings.Contains(out, tc.errorLocation) && !strings.Contains(out, tc.errorLocation) &&
!strings.Contains(out, noSymbolizer) && !strings.Contains(out, noSymbolizer) &&

View File

@ -6,6 +6,7 @@ package reboot_test
import ( import (
"io" "io"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -26,10 +27,14 @@ func overlayDir(dstRoot, srcRoot string) error {
return err return err
} }
return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error { return filepath.WalkDir(srcRoot, func(srcPath string, entry fs.DirEntry, err error) error {
if err != nil || srcPath == srcRoot { if err != nil || srcPath == srcRoot {
return err return err
} }
if filepath.Base(srcPath) == "testdata" {
// We're just building, so no need to copy those.
return fs.SkipDir
}
suffix := strings.TrimPrefix(srcPath, srcRoot) suffix := strings.TrimPrefix(srcPath, srcRoot)
for len(suffix) > 0 && suffix[0] == filepath.Separator { for len(suffix) > 0 && suffix[0] == filepath.Separator {
@ -37,6 +42,7 @@ func overlayDir(dstRoot, srcRoot string) error {
} }
dstPath := filepath.Join(dstRoot, suffix) dstPath := filepath.Join(dstRoot, suffix)
info, err := entry.Info()
perm := info.Mode() & os.ModePerm perm := info.Mode() & os.ModePerm
if info.Mode()&os.ModeSymlink != 0 { if info.Mode()&os.ModeSymlink != 0 {
info, err = os.Stat(srcPath) info, err = os.Stat(srcPath)
@ -46,14 +52,15 @@ func overlayDir(dstRoot, srcRoot string) error {
perm = info.Mode() & os.ModePerm perm = info.Mode() & os.ModePerm
} }
// Always copy directories (don't symlink them). // Always make copies of directories.
// If we add a file in the overlay, we don't want to add it in the original. // If we add a file in the overlay, we don't want to add it in the original.
if info.IsDir() { if info.IsDir() {
return os.MkdirAll(dstPath, perm|0200) return os.MkdirAll(dstPath, perm|0200)
} }
// If the OS supports symlinks, use them instead of copying bytes. // If we can use a hard link, do that instead of copying bytes.
if err := os.Symlink(srcPath, dstPath); err == nil { // Go builds don't like symlinks in some cases, such as go:embed.
if err := os.Link(srcPath, dstPath); err == nil {
return nil return nil
} }

View File

@ -12,6 +12,7 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"testing" "testing"
"time"
) )
func TestRepeatBootstrap(t *testing.T) { func TestRepeatBootstrap(t *testing.T) {
@ -19,16 +20,14 @@ func TestRepeatBootstrap(t *testing.T) {
t.Skipf("skipping test that rebuilds the entire toolchain") t.Skipf("skipping test that rebuilds the entire toolchain")
} }
goroot, err := os.MkdirTemp("", "reboot-goroot") goroot := t.TempDir()
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(goroot)
gorootSrc := filepath.Join(goroot, "src") gorootSrc := filepath.Join(goroot, "src")
overlayStart := time.Now()
if err := overlayDir(gorootSrc, filepath.Join(runtime.GOROOT(), "src")); err != nil { if err := overlayDir(gorootSrc, filepath.Join(runtime.GOROOT(), "src")); err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Logf("GOROOT/src overlay set up in %s", time.Since(overlayStart))
if err := os.WriteFile(filepath.Join(goroot, "VERSION"), []byte(runtime.Version()), 0666); err != nil { if err := os.WriteFile(filepath.Join(goroot, "VERSION"), []byte(runtime.Version()), 0666); err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -95,11 +95,11 @@ type rune = int32
type any = interface{} type any = interface{}
// comparable is an interface that is implemented by all comparable types // comparable is an interface that is implemented by all comparable types
// (booleans, numbers, strings, pointers, channels, interfaces, // (booleans, numbers, strings, pointers, channels, arrays of comparable types,
// arrays of comparable types, structs whose fields are all comparable types). // structs whose fields are all comparable types).
// The comparable interface may only be used as a type parameter constraint, // The comparable interface may only be used as a type parameter constraint,
// not as the type of a variable. // not as the type of a variable.
type comparable comparable type comparable interface{ comparable }
// iota is a predeclared identifier representing the untyped integer ordinal // iota is a predeclared identifier representing the untyped integer ordinal
// number of the current const specification in a (usually parenthesized) // number of the current const specification in a (usually parenthesized)

View File

@ -372,6 +372,8 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte {
// n > 0: at most n subslices; the last subslice will be the unsplit remainder. // n > 0: at most n subslices; the last subslice will be the unsplit remainder.
// n == 0: the result is nil (zero subslices) // n == 0: the result is nil (zero subslices)
// n < 0: all subslices // n < 0: all subslices
//
// To split around the first instance of a separator, see Cut.
func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) } func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) }
// SplitAfterN slices s into subslices after each instance of sep and // SplitAfterN slices s into subslices after each instance of sep and
@ -389,6 +391,8 @@ func SplitAfterN(s, sep []byte, n int) [][]byte {
// the subslices between those separators. // the subslices between those separators.
// If sep is empty, Split splits after each UTF-8 sequence. // If sep is empty, Split splits after each UTF-8 sequence.
// It is equivalent to SplitN with a count of -1. // It is equivalent to SplitN with a count of -1.
//
// To split around the first instance of a separator, see Cut.
func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) } func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) }
// SplitAfter slices s into all subslices after each instance of sep and // SplitAfter slices s into all subslices after each instance of sep and

View File

@ -155,7 +155,7 @@ as follows:
1. Remember I and FP. 1. Remember I and FP.
1. If T has zero size, add T to the stack sequence S and return. 1. If T has zero size, add T to the stack sequence S and return.
1. Try to register-assign V. 1. Try to register-assign V.
1. If step 2 failed, reset I and FP to the values from step 1, add T 1. If step 3 failed, reset I and FP to the values from step 1, add T
to the stack sequence S, and assign V to this field in S. to the stack sequence S, and assign V to this field in S.
Register-assignment of a value V of underlying type T works as follows: Register-assignment of a value V of underlying type T works as follows:

View File

@ -62,8 +62,9 @@ func Compiling(pkgs []string) bool {
// at best instrumentation would cause infinite recursion. // at best instrumentation would cause infinite recursion.
var NoInstrumentPkgs = []string{ var NoInstrumentPkgs = []string{
"runtime/internal/atomic", "runtime/internal/atomic",
"runtime/internal/sys",
"runtime/internal/math", "runtime/internal/math",
"runtime/internal/sys",
"runtime/internal/syscall",
"runtime", "runtime",
"runtime/race", "runtime/race",
"runtime/msan", "runtime/msan",

View File

@ -238,6 +238,15 @@ func (e *escape) goDeferStmt(n *ir.GoDeferStmt) {
fn.SetWrapper(true) fn.SetWrapper(true)
fn.Nname.SetType(types.NewSignature(types.LocalPkg, nil, nil, nil, nil)) fn.Nname.SetType(types.NewSignature(types.LocalPkg, nil, nil, nil, nil))
fn.Body = []ir.Node{call} fn.Body = []ir.Node{call}
if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC {
// If the callee is a named function, link to the original callee.
x := call.X
if x.Op() == ir.ONAME && x.(*ir.Name).Class == ir.PFUNC {
fn.WrappedFunc = call.X.(*ir.Name).Func
} else if x.Op() == ir.OMETHEXPR && ir.MethodExprFunc(x).Nname != nil {
fn.WrappedFunc = ir.MethodExprName(x).Func
}
}
clo := fn.OClosure clo := fn.OClosure
if n.Op() == ir.OGO { if n.Op() == ir.OGO {

View File

@ -10,6 +10,7 @@ import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir" "cmd/compile/internal/ir"
"cmd/compile/internal/logopt" "cmd/compile/internal/logopt"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types" "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) n.SetByval(!loc.addrtaken && !loc.reassigned && n.Type().Size() <= 128)
if !n.Byval() { if !n.Byval() {
n.SetAddrtaken(true) n.SetAddrtaken(true)
if n.Sym().Name == typecheck.LocalDictName {
base.FatalfAt(n.Pos(), "dictionary variable not captured by value")
}
} }
if base.Flag.LowerM > 1 { if base.Flag.LowerM > 1 {

View File

@ -217,6 +217,10 @@ func dumpGlobalConst(n ir.Node) {
if ir.ConstOverflow(v, t) { if ir.ConstOverflow(v, t) {
return 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)) base.Ctxt.DwarfIntConst(base.Ctxt.Pkgpath, n.Sym().Name, types.TypeSymName(t), ir.IntVal(t, v))
} }
@ -263,6 +267,10 @@ func addGCLocals() {
objw.Global(x, int32(len(x.P)), obj.RODATA|obj.DUPOK) objw.Global(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
x.Set(obj.AttrStatic, true) x.Set(obj.AttrStatic, true)
} }
if x := fn.WrapInfo; x != nil && !x.OnList() {
objw.Global(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
x.Set(obj.AttrStatic, true)
}
} }
} }

View File

@ -180,6 +180,14 @@ func ImportData(imports map[string]*types2.Package, data, path string) (pkg *typ
p.doDecl(localpkg, name) 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 // record all referenced packages as imports
list := append(([]*types2.Package)(nil), pkgList[1:]...) list := append(([]*types2.Package)(nil), pkgList[1:]...)
sort.Sort(byPath(list)) sort.Sort(byPath(list))
@ -191,6 +199,11 @@ func ImportData(imports map[string]*types2.Package, data, path string) (pkg *typ
return localpkg, nil return localpkg, nil
} }
type setConstraintArgs struct {
t *types2.TypeParam
constraint types2.Type
}
type iimporter struct { type iimporter struct {
exportVersion int64 exportVersion int64
ipath string ipath string
@ -206,6 +219,9 @@ type iimporter struct {
tparamIndex map[ident]*types2.TypeParam tparamIndex map[ident]*types2.TypeParam
interfaceList []*types2.Interface 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) { func (p *iimporter) doDecl(pkg *types2.Package, name string) {
@ -401,7 +417,11 @@ func (r *importReader) obj(name string) {
} }
iface.MarkImplicit() 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': case 'V':
typ := r.typ() typ := r.typ()

View File

@ -133,6 +133,10 @@ type Func struct {
// function for go:nowritebarrierrec analysis. Only filled in // function for go:nowritebarrierrec analysis. Only filled in
// if nowritebarrierrecCheck != nil. // if nowritebarrierrecCheck != nil.
NWBRCalls *[]SymAndPos NWBRCalls *[]SymAndPos
// For wrapper functions, WrappedFunc point to the original Func.
// Currently only used for go/defer wrappers.
WrappedFunc *Func
} }
func NewFunc(pos src.XPos) *Func { func NewFunc(pos src.XPos) *Func {

View File

@ -20,7 +20,7 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms _32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms _64bit uintptr // size on 64bit platforms
}{ }{
{Func{}, 192, 328}, {Func{}, 196, 336},
{Name{}, 112, 200}, {Name{}, 112, 200},
} }

View File

@ -362,7 +362,7 @@ func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt {
return n return n
} }
// A SwitchStmt is a switch statement: switch Init; Expr { Cases }. // A SwitchStmt is a switch statement: switch Init; Tag { Cases }.
type SwitchStmt struct { type SwitchStmt struct {
miniStmt miniStmt
Tag Node Tag Node

View File

@ -114,7 +114,7 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
case *syntax.CallExpr: case *syntax.CallExpr:
fun := g.expr(expr.Fun) 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: case *syntax.IndexExpr:
args := unpackListExpr(expr.Index) args := unpackListExpr(expr.Index)
@ -206,6 +206,53 @@ func (g *irgen) substType(typ *types.Type, tparams *types.Type, targs []ir.Node)
return newt 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 // selectorExpr resolves the choice of ODOT, ODOTPTR, OMETHVALUE (eventually
// ODOTMETH & ODOTINTER), and OMETHEXPR and deals with embedded fields here rather // ODOTMETH & ODOTINTER), and OMETHEXPR and deals with embedded fields here rather
// than in typecheck.go. // than in typecheck.go.
@ -332,13 +379,13 @@ func (g *irgen) exprs(exprs []syntax.Expr) []ir.Node {
} }
func (g *irgen) compLit(typ types2.Type, lit *syntax.CompositeLit) ir.Node { func (g *irgen) compLit(typ types2.Type, lit *syntax.CompositeLit) ir.Node {
if ptr, ok := types2.StructuralType(typ).(*types2.Pointer); ok { if ptr, ok := types2.CoreType(typ).(*types2.Pointer); ok {
n := ir.NewAddrExpr(g.pos(lit), g.compLit(ptr.Elem(), lit)) n := ir.NewAddrExpr(g.pos(lit), g.compLit(ptr.Elem(), lit))
n.SetOp(ir.OPTRLIT) n.SetOp(ir.OPTRLIT)
return typed(g.typ(typ), n) return typed(g.typ(typ), n)
} }
_, isStruct := types2.StructuralType(typ).(*types2.Struct) _, isStruct := types2.CoreType(typ).(*types2.Struct)
exprs := make([]ir.Node, len(lit.ElemList)) exprs := make([]ir.Node, len(lit.ElemList))
for i, elem := range lit.ElemList { for i, elem := range lit.ElemList {

View File

@ -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 { func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) *ir.BinaryExpr {
n := ir.NewBinaryExpr(pos, op, x, y) n := ir.NewBinaryExpr(pos, op, x, y)
typed(typ, n) typed(typ, n)

View File

@ -410,7 +410,8 @@ func (g *genInst) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
fn, formalParams, formalResults := startClosure(pos, outer, typ) fn, formalParams, formalResults := startClosure(pos, outer, typ)
// This is the dictionary we want to use. // 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 // For the latter, dictVar is a variable in the outer function's scope, set to the subdictionary
// read from the outer function's dictionary. // read from the outer function's dictionary.
var dictVar *ir.Name var dictVar *ir.Name
@ -640,6 +641,11 @@ func (g *genInst) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMe
// over any pointer) // over any pointer)
recvType := nameNode.Type().Recv().Type recvType := nameNode.Type().Recv().Type
recvType = deref(recvType) 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() tparams = recvType.RParams()
} else { } else {
fields := nameNode.Type().TParams().Fields().Slice() 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)) s1 := make([]*types.Type, len(shapes))
for i, t := range shapes { for i, t := range shapes {
var tparam *types.Type var tparam *types.Type
if tparams[i].Kind() == types.TTYPEPARAM { // Shapes are grouped differently for structural types, so we
// Shapes are grouped differently for structural types, so we // pass the type param to Shapify(), so we can distinguish.
// pass the type param to Shapify(), so we can distinguish. tparam = tparams[i]
tparam = tparams[i]
}
if !t.IsShape() { if !t.IsShape() {
s1[i] = typecheck.Shapify(t, i, tparam) s1[i] = typecheck.Shapify(t, i, tparam)
} else { } else {
@ -1055,8 +1059,6 @@ func (subst *subster) node(n ir.Node) ir.Node {
// Transform the conversion, now that we know the // Transform the conversion, now that we know the
// type argument. // type argument.
m = transformConvCall(call) m = transformConvCall(call)
// CONVIFACE transformation was already done in noder2
assert(m.Op() != ir.OCONVIFACE)
case ir.OMETHVALUE, ir.OMETHEXPR: case ir.OMETHVALUE, ir.OMETHEXPR:
// Redo the transformation of OXDOT, now that we // Redo the transformation of OXDOT, now that we
@ -1076,14 +1078,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
case ir.ONAME: case ir.ONAME:
name := call.X.Name() name := call.X.Name()
if name.BuiltinOp != ir.OXXX { if name.BuiltinOp != ir.OXXX {
switch name.BuiltinOp { m = transformBuiltin(call)
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")
}
} else { } else {
// This is the case of a function value that was a // This is the case of a function value that was a
// type parameter (implied to be a function via 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) newfn.Dcl = append(newfn.Dcl, ldict)
as := ir.NewAssignStmt(x.Pos(), ldict, cdict) as := ir.NewAssignStmt(x.Pos(), ldict, cdict)
as.SetTypecheck(1) as.SetTypecheck(1)
ldict.Defn = as
newfn.Body.Append(as) newfn.Body.Append(as)
// Create inst info for the instantiated closure. The dict // Create inst info for the instantiated closure. The dict
@ -1183,6 +1179,26 @@ func (subst *subster) node(n ir.Node) ir.Node {
subst.g.newInsts = append(subst.g.newInsts, m.(*ir.ClosureExpr).Func) subst.g.newInsts = append(subst.g.newInsts, m.(*ir.ClosureExpr).Func)
m.(*ir.ClosureExpr).SetInit(subst.list(x.Init())) m.(*ir.ClosureExpr).SetInit(subst.list(x.Init()))
case ir.OSWITCH:
m := m.(*ir.SwitchStmt)
if m.Tag != nil && m.Tag.Op() == ir.OTYPESW {
break // Nothing to do here for type switches.
}
if m.Tag != nil && !m.Tag.Type().IsInterface() && m.Tag.Type().HasShape() {
// To implement a switch on a value that is or has a type parameter, we first convert
// that thing we're switching on to an interface{}.
m.Tag = assignconvfn(m.Tag, types.Types[types.TINTER])
}
for _, c := range m.Cases {
for i, x := range c.List {
// If we have a case that is or has a type parameter, convert that case
// to an interface{}.
if !x.Type().IsInterface() && x.Type().HasShape() {
c.List[i] = assignconvfn(x, types.Types[types.TINTER])
}
}
}
} }
return m return m
} }

View File

@ -242,7 +242,7 @@ func transformCompare(n *ir.BinaryExpr) {
aop, _ := typecheck.Assignop(rt, lt) aop, _ := typecheck.Assignop(rt, lt)
if aop != ir.OXXX { if aop != ir.OXXX {
types.CalcSize(rt) types.CalcSize(rt)
if rt.HasTParam() || rt.IsInterface() == lt.IsInterface() || rt.Size() >= 1<<16 { if rt.HasShape() || rt.IsInterface() == lt.IsInterface() || rt.Size() >= 1<<16 {
r = ir.NewConvExpr(base.Pos, aop, lt, r) r = ir.NewConvExpr(base.Pos, aop, lt, r)
r.SetTypecheck(1) r.SetTypecheck(1)
} }

View File

@ -1338,10 +1338,10 @@ func (w *writer) compLit(lit *syntax.CompositeLit) {
w.typ(tv.Type) w.typ(tv.Type)
typ := tv.Type typ := tv.Type
if ptr, ok := types2.StructuralType(typ).(*types2.Pointer); ok { if ptr, ok := types2.CoreType(typ).(*types2.Pointer); ok {
typ = ptr.Elem() typ = ptr.Elem()
} }
str, isStruct := types2.StructuralType(typ).(*types2.Struct) str, isStruct := types2.CoreType(typ).(*types2.Struct)
w.len(len(lit.ElemList)) w.len(len(lit.ElemList))
for i, elem := range lit.ElemList { for i, elem := range lit.ElemList {

View File

@ -1457,7 +1457,7 @@ func WriteBasicTypes() {
type typeAndStr struct { type typeAndStr struct {
t *types.Type t *types.Type
short string // "short" here means NameString short string // "short" here means TypeSymName
regular string regular string
} }

View File

@ -256,7 +256,7 @@
(Leq64F ...) => (FLED ...) (Leq64F ...) => (FLED ...)
(Leq32F ...) => (FLES ...) (Leq32F ...) => (FLES ...)
(EqPtr x y) => (SEQZ (SUB <x.Type> x y)) (EqPtr x y) => (SEQZ (SUB <typ.Uintptr> x y))
(Eq64 x y) => (SEQZ (SUB <x.Type> x y)) (Eq64 x y) => (SEQZ (SUB <x.Type> x y))
(Eq32 x y) => (SEQZ (SUB <x.Type> (ZeroExt32to64 x) (ZeroExt32to64 y))) (Eq32 x y) => (SEQZ (SUB <x.Type> (ZeroExt32to64 x) (ZeroExt32to64 y)))
(Eq16 x y) => (SEQZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y))) (Eq16 x y) => (SEQZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y)))
@ -264,7 +264,7 @@
(Eq64F ...) => (FEQD ...) (Eq64F ...) => (FEQD ...)
(Eq32F ...) => (FEQS ...) (Eq32F ...) => (FEQS ...)
(NeqPtr x y) => (SNEZ (SUB <x.Type> x y)) (NeqPtr x y) => (SNEZ (SUB <typ.Uintptr> x y))
(Neq64 x y) => (SNEZ (SUB <x.Type> x y)) (Neq64 x y) => (SNEZ (SUB <x.Type> x y))
(Neq32 x y) => (SNEZ (SUB <x.Type> (ZeroExt32to64 x) (ZeroExt32to64 y))) (Neq32 x y) => (SNEZ (SUB <x.Type> (ZeroExt32to64 x) (ZeroExt32to64 y)))
(Neq16 x y) => (SNEZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y))) (Neq16 x y) => (SNEZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y)))

View File

@ -906,7 +906,7 @@ func (po *poset) Ordered(n1, n2 *Value) bool {
return i1 != i2 && po.reaches(i1, i2, true) return i1 != i2 && po.reaches(i1, i2, true)
} }
// Ordered reports whether n1<=n2. It returns false either when it is // OrderedOrEqual reports whether n1<=n2. It returns false either when it is
// certain that n1<=n2 is false, or if there is not enough information // certain that n1<=n2 is false, or if there is not enough information
// to tell. // to tell.
// Complexity is O(n). // Complexity is O(n).

View File

@ -1124,13 +1124,14 @@ func rewriteValueRISCV64_OpEqPtr(v *Value) bool {
v_1 := v.Args[1] v_1 := v.Args[1]
v_0 := v.Args[0] v_0 := v.Args[0]
b := v.Block b := v.Block
typ := &b.Func.Config.Types
// match: (EqPtr x y) // match: (EqPtr x y)
// result: (SEQZ (SUB <x.Type> x y)) // result: (SEQZ (SUB <typ.Uintptr> x y))
for { for {
x := v_0 x := v_0
y := v_1 y := v_1
v.reset(OpRISCV64SEQZ) v.reset(OpRISCV64SEQZ)
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type) v0 := b.NewValue0(v.Pos, OpRISCV64SUB, typ.Uintptr)
v0.AddArg2(x, y) v0.AddArg2(x, y)
v.AddArg(v0) v.AddArg(v0)
return true return true
@ -2673,13 +2674,14 @@ func rewriteValueRISCV64_OpNeqPtr(v *Value) bool {
v_1 := v.Args[1] v_1 := v.Args[1]
v_0 := v.Args[0] v_0 := v.Args[0]
b := v.Block b := v.Block
typ := &b.Func.Config.Types
// match: (NeqPtr x y) // match: (NeqPtr x y)
// result: (SNEZ (SUB <x.Type> x y)) // result: (SNEZ (SUB <typ.Uintptr> x y))
for { for {
x := v_0 x := v_0
y := v_1 y := v_1
v.reset(OpRISCV64SNEZ) v.reset(OpRISCV64SNEZ)
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type) v0 := b.NewValue0(v.Pos, OpRISCV64SUB, typ.Uintptr)
v0.AddArg2(x, y) v0.AddArg2(x, y)
v.AddArg(v0) v.AddArg(v0)
return true return true

View File

@ -6768,6 +6768,34 @@ func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym {
return x return x
} }
// for wrapper, emit info of wrapped function.
func emitWrappedFuncInfo(e *ssafn, pp *objw.Progs) {
if base.Ctxt.Flag_linkshared {
// Relative reference (SymPtrOff) to another shared object doesn't work.
// Unfortunate.
return
}
wfn := e.curfn.WrappedFunc
if wfn == nil {
return
}
wsym := wfn.Linksym()
x := base.Ctxt.LookupInit(fmt.Sprintf("%s.wrapinfo", wsym.Name), func(x *obj.LSym) {
objw.SymPtrOff(x, 0, wsym)
x.Set(obj.AttrContentAddressable, true)
})
e.curfn.LSym.Func().WrapInfo = x
// Emit a funcdata pointing at the wrap info data.
p := pp.Prog(obj.AFUNCDATA)
p.From.SetConst(objabi.FUNCDATA_WrapInfo)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = x
}
// genssa appends entries to pp for each instruction in f. // genssa appends entries to pp for each instruction in f.
func genssa(f *ssa.Func, pp *objw.Progs) { func genssa(f *ssa.Func, pp *objw.Progs) {
var s State var s State
@ -6790,6 +6818,8 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
p.To.Sym = openDeferInfo p.To.Sym = openDeferInfo
} }
emitWrappedFuncInfo(e, pp)
// Remember where each block starts. // Remember where each block starts.
s.bstart = make([]*obj.Prog, f.NumBlocks()) s.bstart = make([]*obj.Prog, f.NumBlocks())
s.pp = pp s.pp = pp

View File

@ -6,7 +6,7 @@ package main
import ( import (
"fmt" "fmt"
"./mysort" "cmd/compile/internal/test/testdata/mysort"
) )
type MyString struct { type MyString struct {

View File

@ -1851,7 +1851,10 @@ func (w *exportWriter) expr(n ir.Node) {
n := n.(*ir.ClosureExpr) n := n.(*ir.ClosureExpr)
w.op(ir.OCLOSURE) w.op(ir.OCLOSURE)
w.pos(n.Pos()) w.pos(n.Pos())
old := w.currPkg
w.setPkg(n.Type().Pkg(), true)
w.signature(n.Type()) w.signature(n.Type())
w.setPkg(old, true)
// Write out id for the Outer of each conditional variable. The // Write out id for the Outer of each conditional variable. The
// conditional variable itself for this closure will be re-created // conditional variable itself for this closure will be re-created

View File

@ -354,15 +354,18 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name {
// declaration before recursing. // declaration before recursing.
n := importtype(pos, sym) n := importtype(pos, sym)
t := n.Type() 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' { if tag == 'U' {
rparams := r.typeList() rparams := r.typeList()
t.SetRParams(rparams) t.SetRParams(rparams)
} }
// We also need to defer width calculations until
// after the underlying type has been assigned.
types.DeferCheckSize()
deferDoInst()
underlying := r.typ() underlying := r.typ()
t.SetUnderlying(underlying) t.SetUnderlying(underlying)
@ -1371,7 +1374,9 @@ func (r *importReader) node() ir.Node {
case ir.OCLOSURE: case ir.OCLOSURE:
//println("Importing CLOSURE") //println("Importing CLOSURE")
pos := r.pos() pos := r.pos()
r.setPkg()
typ := r.signature(nil, nil) typ := r.signature(nil, nil)
r.setPkg()
// All the remaining code below is similar to (*noder).funcLit(), but // All the remaining code below is similar to (*noder).funcLit(), but
// with Dcls and ClosureVars lists already set up // with Dcls and ClosureVars lists already set up

View File

@ -1424,6 +1424,68 @@ func genericTypeName(sym *types.Sym) string {
return sym.Name[0:strings.Index(sym.Name, "[")] 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 // 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. // 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 // 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 // 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. // the same underlying type or they are both pointer types.
// //
// tparam is the associated typeparam. If there is a structural type for // tparam is the associated typeparam - it must be TTYPEPARAM type. If there is a
// the associated type param (not common), then a pointer type t is mapped to its // structural type for the associated type param (not common), then a pointer type t
// underlying type, rather than being merged with other pointers. // 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 // 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 // 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. // instantiation.
func Shapify(t *types.Type, index int, tparam *types.Type) *types.Type { func Shapify(t *types.Type, index int, tparam *types.Type) *types.Type {
assert(!t.IsShape()) 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. // Map all types with the same underlying type to the same shape.
u := t.Underlying() u := t.Underlying()

View File

@ -72,6 +72,7 @@ const (
fmtDebug fmtDebug
fmtTypeID fmtTypeID
fmtTypeIDName fmtTypeIDName
fmtTypeIDHash
) )
// Sym // Sym
@ -144,10 +145,21 @@ func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
if q := pkgqual(s.Pkg, verb, mode); q != "" { if q := pkgqual(s.Pkg, verb, mode); q != "" {
b.WriteString(q) b.WriteString(q)
b.WriteByte('.') b.WriteByte('.')
if mode == fmtTypeIDName { switch mode {
case fmtTypeIDName:
// If name is a generic instantiation, it might have local package placeholders // If name is a generic instantiation, it might have local package placeholders
// in it. Replace those placeholders with the package name. See issue 49547. // in it. Replace those placeholders with the package name. See issue 49547.
name = strings.Replace(name, LocalPkg.Prefix, q, -1) name = strings.Replace(name, LocalPkg.Prefix, q, -1)
case fmtTypeIDHash:
// If name is a generic instantiation, don't hash the instantiating types.
// This isn't great, but it is safe. If we hash the instantiating types, then
// we need to make sure they have just the package name. At this point, they
// either have "", or the whole package path, and it is hard to reconcile
// the two without depending on -p (which we might do someday).
// See issue 51250.
if i := strings.Index(name, "["); i >= 0 {
name = name[:i]
}
} }
} }
b.WriteString(name) b.WriteString(name)
@ -173,7 +185,7 @@ func pkgqual(pkg *Pkg, verb rune, mode fmtMode) string {
case fmtDebug: case fmtDebug:
return pkg.Name return pkg.Name
case fmtTypeIDName: case fmtTypeIDName, fmtTypeIDHash:
// dcommontype, typehash // dcommontype, typehash
return pkg.Name return pkg.Name
@ -331,7 +343,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
if t == AnyType || t == ByteType || t == RuneType { if t == AnyType || t == ByteType || t == RuneType {
// in %-T mode collapse predeclared aliases with their originals. // in %-T mode collapse predeclared aliases with their originals.
switch mode { switch mode {
case fmtTypeIDName, fmtTypeID: case fmtTypeIDName, fmtTypeIDHash, fmtTypeID:
t = Types[t.Kind()] t = Types[t.Kind()]
default: default:
sconv2(b, t.Sym(), 'S', mode) sconv2(b, t.Sym(), 'S', mode)
@ -422,7 +434,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
case TPTR: case TPTR:
b.WriteByte('*') b.WriteByte('*')
switch mode { switch mode {
case fmtTypeID, fmtTypeIDName: case fmtTypeID, fmtTypeIDName, fmtTypeIDHash:
if verb == 'S' { if verb == 'S' {
tconv2(b, t.Elem(), 'S', mode, visited) tconv2(b, t.Elem(), 'S', mode, visited)
return return
@ -484,7 +496,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
case IsExported(f.Sym.Name): case IsExported(f.Sym.Name):
sconv2(b, f.Sym, 'S', mode) sconv2(b, f.Sym, 'S', mode)
default: default:
if mode != fmtTypeIDName { if mode != fmtTypeIDName && mode != fmtTypeIDHash {
mode = fmtTypeID mode = fmtTypeID
} }
sconv2(b, f.Sym, 'v', mode) sconv2(b, f.Sym, 'v', mode)
@ -554,7 +566,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
b.WriteByte(byte(open)) b.WriteByte(byte(open))
fieldVerb := 'v' fieldVerb := 'v'
switch mode { switch mode {
case fmtTypeID, fmtTypeIDName, fmtGo: case fmtTypeID, fmtTypeIDName, fmtTypeIDHash, fmtGo:
// no argument names on function signature, and no "noescape"/"nosplit" tags // no argument names on function signature, and no "noescape"/"nosplit" tags
fieldVerb = 'S' fieldVerb = 'S'
} }
@ -657,7 +669,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 // Compute tsym, the symbol that would normally be used as
// the field name when embedding f.Type. // 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. // and deduplicate.
typ := f.Type typ := f.Type
if typ.IsPtr() { if typ.IsPtr() {
@ -688,7 +700,7 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
if name == ".F" { if name == ".F" {
name = "F" // Hack for toolstash -cmp. name = "F" // Hack for toolstash -cmp.
} }
if !IsExported(name) && mode != fmtTypeIDName { if !IsExported(name) && mode != fmtTypeIDName && mode != fmtTypeIDHash {
name = sconv(s, 0, mode) // qualify non-exported names (used on structs, not on funarg) name = sconv(s, 0, mode) // qualify non-exported names (used on structs, not on funarg)
} }
} else { } else {
@ -756,7 +768,7 @@ func FmtConst(v constant.Value, sharp bool) string {
// TypeHash computes a hash value for type t to use in type switch statements. // TypeHash computes a hash value for type t to use in type switch statements.
func TypeHash(t *Type) uint32 { func TypeHash(t *Type) uint32 {
p := t.NameString() p := tconv(t, 0, fmtTypeIDHash)
// Using MD5 is overkill, but reduces accidental collisions. // Using MD5 is overkill, but reduces accidental collisions.
h := md5.Sum([]byte(p)) h := md5.Sum([]byte(p))

View File

@ -204,12 +204,12 @@ type Info struct {
// qualified identifiers are collected in the Uses map. // qualified identifiers are collected in the Uses map.
Types map[syntax.Expr]TypeAndValue Types map[syntax.Expr]TypeAndValue
// Instances maps identifiers denoting parameterized types or functions to // Instances maps identifiers denoting generic types or functions to their
// their type arguments and instantiated type. // type arguments and instantiated type.
// //
// For example, Instances will map the identifier for 'T' in the type // For example, Instances will map the identifier for 'T' in the type
// instantiation T[int, string] to the type arguments [int, string] and // instantiation T[int, string] to the type arguments [int, string] and
// resulting instantiated *Named type. Given a parameterized function // resulting instantiated *Named type. Given a generic function
// func F[A any](A), Instances will map the identifier for 'F' in the call // func F[A any](A), Instances will map the identifier for 'F' in the call
// expression F(int(1)) to the inferred type arguments [int], and resulting // expression F(int(1)) to the inferred type arguments [int], and resulting
// instantiated *Signature. // instantiated *Signature.
@ -421,25 +421,45 @@ func (conf *Config) Check(path string, files []*syntax.File, info *Info) (*Packa
} }
// AssertableTo reports whether a value of type V can be asserted to have type T. // AssertableTo reports whether a value of type V can be asserted to have type T.
//
// The behavior of AssertableTo is undefined in two cases:
// - if V is a generalized interface; i.e., an interface that may only be used
// as a type constraint in Go code
// - if T is an uninstantiated generic type
func AssertableTo(V *Interface, T Type) bool { func AssertableTo(V *Interface, T Type) bool {
m, _ := (*Checker)(nil).assertableTo(V, T) // Checker.newAssertableTo suppresses errors for invalid types, so we need special
return m == nil // handling here.
if T.Underlying() == Typ[Invalid] {
return false
}
return (*Checker)(nil).newAssertableTo(V, T) == nil
} }
// AssignableTo reports whether a value of type V is assignable to a variable of type T. // AssignableTo reports whether a value of type V is assignable to a variable
// of type T.
//
// The behavior of AssignableTo is undefined if V or T is an uninstantiated
// generic type.
func AssignableTo(V, T Type) bool { func AssignableTo(V, T Type) bool {
x := operand{mode: value, typ: V} x := operand{mode: value, typ: V}
ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x
return ok return ok
} }
// ConvertibleTo reports whether a value of type V is convertible to a value of type T. // ConvertibleTo reports whether a value of type V is convertible to a value of
// type T.
//
// The behavior of ConvertibleTo is undefined if V or T is an uninstantiated
// generic type.
func ConvertibleTo(V, T Type) bool { func ConvertibleTo(V, T Type) bool {
x := operand{mode: value, typ: V} x := operand{mode: value, typ: V}
return x.convertibleTo(nil, T, nil) // check not needed for non-constant x return x.convertibleTo(nil, T, nil) // check not needed for non-constant x
} }
// Implements reports whether type V implements interface T. // Implements reports whether type V implements interface T.
//
// The behavior of Implements is undefined if V is an uninstantiated generic
// type.
func Implements(V Type, T *Interface) bool { func Implements(V Type, T *Interface) bool {
if T.Empty() { if T.Empty() {
// All types (even Typ[Invalid]) implement the empty interface. // All types (even Typ[Invalid]) implement the empty interface.

View File

@ -12,6 +12,7 @@ import (
"internal/testenv" "internal/testenv"
"reflect" "reflect"
"regexp" "regexp"
"sort"
"strings" "strings"
"testing" "testing"
@ -403,69 +404,61 @@ func TestTypesInfo(t *testing.T) {
} }
func TestInstanceInfo(t *testing.T) { func TestInstanceInfo(t *testing.T) {
var tests = []struct { const lib = `package lib
src string
func F[P any](P) {}
type T[P any] []P
`
type testInst struct {
name string name string
targs []string targs []string
typ string typ string
}
var tests = []struct {
src string
instances []testInst // recorded instances in source order
}{ }{
{`package p0; func f[T any](T) {}; func _() { f(42) }`, {`package p0; func f[T any](T) {}; func _() { f(42) }`,
`f`, []testInst{{`f`, []string{`int`}, `func(int)`}},
[]string{`int`},
`func(int)`,
}, },
{`package p1; func f[T any](T) T { panic(0) }; func _() { f('@') }`, {`package p1; func f[T any](T) T { panic(0) }; func _() { f('@') }`,
`f`, []testInst{{`f`, []string{`rune`}, `func(rune) rune`}},
[]string{`rune`},
`func(rune) rune`,
}, },
{`package p2; func f[T any](...T) T { panic(0) }; func _() { f(0i) }`, {`package p2; func f[T any](...T) T { panic(0) }; func _() { f(0i) }`,
`f`, []testInst{{`f`, []string{`complex128`}, `func(...complex128) complex128`}},
[]string{`complex128`},
`func(...complex128) complex128`,
}, },
{`package p3; func f[A, B, C any](A, *B, []C) {}; func _() { f(1.2, new(string), []byte{}) }`, {`package p3; func f[A, B, C any](A, *B, []C) {}; func _() { f(1.2, new(string), []byte{}) }`,
`f`, []testInst{{`f`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`}},
[]string{`float64`, `string`, `byte`},
`func(float64, *string, []byte)`,
}, },
{`package p4; func f[A, B any](A, *B, ...[]B) {}; func _() { f(1.2, new(byte)) }`, {`package p4; func f[A, B any](A, *B, ...[]B) {}; func _() { f(1.2, new(byte)) }`,
`f`, []testInst{{`f`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`}},
[]string{`float64`, `byte`},
`func(float64, *byte, ...[]byte)`,
}, },
// we don't know how to translate these but we can type-check them // we don't know how to translate these but we can type-check them
{`package q0; type T struct{}; func (T) m[P any](P) {}; func _(x T) { x.m(42) }`, {`package q0; type T struct{}; func (T) m[P any](P) {}; func _(x T) { x.m(42) }`,
`m`, []testInst{{`m`, []string{`int`}, `func(int)`}},
[]string{`int`},
`func(int)`,
}, },
{`package q1; type T struct{}; func (T) m[P any](P) P { panic(0) }; func _(x T) { x.m(42) }`, {`package q1; type T struct{}; func (T) m[P any](P) P { panic(0) }; func _(x T) { x.m(42) }`,
`m`, []testInst{{`m`, []string{`int`}, `func(int) int`}},
[]string{`int`},
`func(int) int`,
}, },
{`package q2; type T struct{}; func (T) m[P any](...P) P { panic(0) }; func _(x T) { x.m(42) }`, {`package q2; type T struct{}; func (T) m[P any](...P) P { panic(0) }; func _(x T) { x.m(42) }`,
`m`, []testInst{{`m`, []string{`int`}, `func(...int) int`}},
[]string{`int`},
`func(...int) int`,
}, },
{`package q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C) {}; func _(x T) { x.m(1.2, new(string), []byte{}) }`, {`package q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C) {}; func _(x T) { x.m(1.2, new(string), []byte{}) }`,
`m`, []testInst{{`m`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`}},
[]string{`float64`, `string`, `byte`},
`func(float64, *string, []byte)`,
}, },
{`package q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B) {}; func _(x T) { x.m(1.2, new(byte)) }`, {`package q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B) {}; func _(x T) { x.m(1.2, new(byte)) }`,
`m`, []testInst{{`m`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`}},
[]string{`float64`, `byte`},
`func(float64, *byte, ...[]byte)`,
}, },
{`package r0; type T[P any] struct{}; func (_ T[P]) m[Q any](Q) {}; func _[P any](x T[P]) { x.m(42) }`, {`package r0; type T[P1 any] struct{}; func (_ T[P2]) m[Q any](Q) {}; func _[P3 any](x T[P3]) { x.m(42) }`,
`m`, []testInst{
[]string{`int`}, {`T`, []string{`P2`}, `struct{}`},
`func(int)`, {`T`, []string{`P3`}, `struct{}`},
{`m`, []string{`int`}, `func(int)`},
},
}, },
// TODO(gri) record method type parameters in syntax.FuncType so we can check this // TODO(gri) record method type parameters in syntax.FuncType so we can check this
// {`package r1; type T interface{ m[P any](P) }; func _(x T) { x.m(4.2) }`, // {`package r1; type T interface{ m[P any](P) }; func _(x T) { x.m(4.2) }`,
@ -474,97 +467,113 @@ func TestInstanceInfo(t *testing.T) {
// `func(float64)`, // `func(float64)`,
// }, // },
{`package s1; func f[T any, P interface{~*T}](x T) {}; func _(x string) { f(x) }`, {`package s1; func f[T any, P interface{*T}](x T) {}; func _(x string) { f(x) }`,
`f`, []testInst{{`f`, []string{`string`, `*string`}, `func(x string)`}},
[]string{`string`, `*string`},
`func(x string)`,
}, },
{`package s2; func f[T any, P interface{~*T}](x []T) {}; func _(x []int) { f(x) }`, {`package s2; func f[T any, P interface{*T}](x []T) {}; func _(x []int) { f(x) }`,
`f`, []testInst{{`f`, []string{`int`, `*int`}, `func(x []int)`}},
[]string{`int`, `*int`},
`func(x []int)`,
}, },
{`package s3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]](x []T) {}; func _(x []int) { f(x) }`, {`package s3; type C[T any] interface{chan<- T}; func f[T any, P C[T]](x []T) {}; func _(x []int) { f(x) }`,
`f`, []testInst{
[]string{`int`, `chan<- int`}, {`C`, []string{`T`}, `interface{chan<- T}`},
`func(x []int)`, {`f`, []string{`int`, `chan<- int`}, `func(x []int)`},
},
}, },
{`package s4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T) {}; func _(x []int) { f(x) }`, {`package s4; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T) {}; func _(x []int) { f(x) }`,
`f`, []testInst{
[]string{`int`, `chan<- int`, `chan<- []*chan<- int`}, {`C`, []string{`T`}, `interface{chan<- T}`},
`func(x []int)`, {`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
{`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func(x []int)`},
},
}, },
{`package t1; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = f[string] }`, {`package t1; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = f[string] }`,
`f`, []testInst{{`f`, []string{`string`, `*string`}, `func() string`}},
[]string{`string`, `*string`},
`func() string`,
}, },
{`package t2; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = (f[string]) }`, {`package t2; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = (f[string]) }`,
`f`, []testInst{{`f`, []string{`string`, `*string`}, `func() string`}},
[]string{`string`, `*string`},
`func() string`,
}, },
{`package t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`, {`package t3; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
`f`, []testInst{
[]string{`int`, `chan<- int`, `chan<- []*chan<- int`}, {`C`, []string{`T`}, `interface{chan<- T}`},
`func() []int`, {`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
{`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`},
},
}, },
{`package t4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`, {`package t4; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = (f[int]) }`,
`f`, []testInst{
[]string{`int`, `chan<- int`, `chan<- []*chan<- int`}, {`C`, []string{`T`}, `interface{chan<- T}`},
`func() []int`, {`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
{`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`},
},
}, },
{`package i0; import lib "generic_lib"; func _() { lib.F(42) }`, {`package i0; import "lib"; func _() { lib.F(42) }`,
`F`, []testInst{{`F`, []string{`int`}, `func(int)`}},
[]string{`int`},
`func(int)`,
}, },
{`package duplfunc0; func f[T any](T) {}; func _() { f(42); f("foo"); f[int](3) }`,
[]testInst{
{`f`, []string{`int`}, `func(int)`},
{`f`, []string{`string`}, `func(string)`},
{`f`, []string{`int`}, `func(int)`},
},
},
{`package duplfunc1; import "lib"; func _() { lib.F(42); lib.F("foo"); lib.F(3) }`,
[]testInst{
{`F`, []string{`int`}, `func(int)`},
{`F`, []string{`string`}, `func(string)`},
{`F`, []string{`int`}, `func(int)`},
},
},
{`package type0; type T[P interface{~int}] struct{ x P }; var _ T[int]`, {`package type0; type T[P interface{~int}] struct{ x P }; var _ T[int]`,
`T`, []testInst{{`T`, []string{`int`}, `struct{x int}`}},
[]string{`int`},
`struct{x int}`,
}, },
{`package type1; type T[P interface{~int}] struct{ x P }; var _ (T[int])`, {`package type1; type T[P interface{~int}] struct{ x P }; var _ (T[int])`,
`T`, []testInst{{`T`, []string{`int`}, `struct{x int}`}},
[]string{`int`},
`struct{x int}`,
}, },
{`package type2; type T[P interface{~int}] struct{ x P }; var _ T[(int)]`, {`package type2; type T[P interface{~int}] struct{ x P }; var _ T[(int)]`,
`T`, []testInst{{`T`, []string{`int`}, `struct{x int}`}},
[]string{`int`},
`struct{x int}`,
}, },
{`package type3; type T[P1 interface{~[]P2}, P2 any] struct{ x P1; y P2 }; var _ T[[]int, int]`, {`package type3; type T[P1 interface{~[]P2}, P2 any] struct{ x P1; y P2 }; var _ T[[]int, int]`,
`T`, []testInst{{`T`, []string{`[]int`, `int`}, `struct{x []int; y int}`}},
[]string{`[]int`, `int`},
`struct{x []int; y int}`,
}, },
{`package type4; import lib "generic_lib"; var _ lib.T[int]`, {`package type4; import "lib"; var _ lib.T[int]`,
`T`, []testInst{{`T`, []string{`int`}, `[]int`}},
[]string{`int`}, },
`[]int`,
{`package dupltype0; type T[P interface{~int}] struct{ x P }; var x T[int]; var y T[int]`,
[]testInst{
{`T`, []string{`int`}, `struct{x int}`},
{`T`, []string{`int`}, `struct{x int}`},
},
},
{`package dupltype1; type T[P ~int] struct{ x P }; func (r *T[Q]) add(z T[Q]) { r.x += z.x }`,
[]testInst{
{`T`, []string{`Q`}, `struct{x Q}`},
{`T`, []string{`Q`}, `struct{x Q}`},
},
},
{`package dupltype1; import "lib"; var x lib.T[int]; var y lib.T[int]; var z lib.T[string]`,
[]testInst{
{`T`, []string{`int`}, `[]int`},
{`T`, []string{`int`}, `[]int`},
{`T`, []string{`string`}, `[]string`},
},
}, },
} }
for _, test := range tests { for _, test := range tests {
const lib = `package generic_lib
func F[P any](P) {}
type T[P any] []P
`
imports := make(testImporter) imports := make(testImporter)
conf := Config{Importer: imports} conf := Config{Importer: imports}
instances := make(map[*syntax.Name]Instance) instMap := make(map[*syntax.Name]Instance)
uses := make(map[*syntax.Name]Object) useMap := make(map[*syntax.Name]Object)
makePkg := func(src string) *Package { makePkg := func(src string) *Package {
f, err := parseSrc("p.go", src) f, err := parseSrc("p.go", src)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
pkg, err := conf.Check("", []*syntax.File{f}, &Info{Instances: instances, Uses: uses}) pkg, err := conf.Check("", []*syntax.File{f}, &Info{Instances: instMap, Uses: useMap})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -574,60 +583,72 @@ type T[P any] []P
makePkg(lib) makePkg(lib)
pkg := makePkg(test.src) pkg := makePkg(test.src)
// look for instance information t.Run(pkg.Name(), func(t *testing.T) {
var targs []Type // Sort instances in source order for stability.
var typ Type instances := sortedInstances(instMap)
for ident, inst := range instances { if got, want := len(instances), len(test.instances); got != want {
if syntax.String(ident) == test.name { t.Fatalf("got %d instances, want %d", got, want)
for i := 0; i < inst.TypeArgs.Len(); i++ { }
targs = append(targs, inst.TypeArgs.At(i))
}
typ = inst.Type
// Check that we can find the corresponding parameterized type. // Pairwise compare with the expected instances.
ptype := uses[ident].Type() for ii, inst := range instances {
var targs []Type
for i := 0; i < inst.Inst.TypeArgs.Len(); i++ {
targs = append(targs, inst.Inst.TypeArgs.At(i))
}
typ := inst.Inst.Type
testInst := test.instances[ii]
if got := inst.Name.Value; got != testInst.name {
t.Fatalf("got name %s, want %s", got, testInst.name)
}
if len(targs) != len(testInst.targs) {
t.Fatalf("got %d type arguments; want %d", len(targs), len(testInst.targs))
}
for i, targ := range targs {
if got := targ.String(); got != testInst.targs[i] {
t.Errorf("type argument %d: got %s; want %s", i, got, testInst.targs[i])
}
}
if got := typ.Underlying().String(); got != testInst.typ {
t.Errorf("package %s: got %s; want %s", pkg.Name(), got, testInst.typ)
}
// Verify the invariant that re-instantiating the corresponding generic
// type with TypeArgs results in an identical instance.
ptype := useMap[inst.Name].Type()
lister, _ := ptype.(interface{ TypeParams() *TypeParamList }) lister, _ := ptype.(interface{ TypeParams() *TypeParamList })
if lister == nil || lister.TypeParams().Len() == 0 { if lister == nil || lister.TypeParams().Len() == 0 {
t.Errorf("package %s: info.Types[%v] = %v, want parameterized type", pkg.Name(), ident, ptype) t.Fatalf("info.Types[%v] = %v, want parameterized type", inst.Name, ptype)
continue
} }
// Verify the invariant that re-instantiating the generic type with
// TypeArgs results in an equivalent type.
inst2, err := Instantiate(nil, ptype, targs, true) inst2, err := Instantiate(nil, ptype, targs, true)
if err != nil { if err != nil {
t.Errorf("Instantiate(%v, %v) failed: %v", ptype, targs, err) t.Errorf("Instantiate(%v, %v) failed: %v", ptype, targs, err)
} }
if !Identical(inst.Type, inst2) { if !Identical(inst.Inst.Type, inst2) {
t.Errorf("%v and %v are not identical", inst.Type, inst2) t.Errorf("%v and %v are not identical", inst.Inst.Type, inst2)
} }
break
} }
} })
if targs == nil {
t.Errorf("package %s: no instance information found for %s", pkg.Name(), test.name)
continue
}
// check that type arguments are correct
if len(targs) != len(test.targs) {
t.Errorf("package %s: got %d type arguments; want %d", pkg.Name(), len(targs), len(test.targs))
continue
}
for i, targ := range targs {
if got := targ.String(); got != test.targs[i] {
t.Errorf("package %s, %d. type argument: got %s; want %s", pkg.Name(), i, got, test.targs[i])
continue
}
}
// check that the types match
if got := typ.Underlying().String(); got != test.typ {
t.Errorf("package %s: got %s; want %s", pkg.Name(), got, test.typ)
}
} }
} }
type recordedInstance struct {
Name *syntax.Name
Inst Instance
}
func sortedInstances(m map[*syntax.Name]Instance) (instances []recordedInstance) {
for id, inst := range m {
instances = append(instances, recordedInstance{id, inst})
}
sort.Slice(instances, func(i, j int) bool {
return instances[i].Name.Pos().Cmp(instances[j].Name.Pos()) < 0
})
return instances
}
func TestDefsInfo(t *testing.T) { func TestDefsInfo(t *testing.T) {
var tests = []struct { var tests = []struct {
src string src string
@ -1697,7 +1718,7 @@ func F(){
var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F
var a []int var a []int
for i, x := range /*i=undef*/ /*x=var:16*/ a /*i=var:20*/ /*x=var:20*/ { _ = i; _ = x } for i, x := range a /*i=undef*/ /*x=var:16*/ { _ = i; _ = x }
var i interface{} var i interface{}
switch y := i.(type) { /*y=undef*/ switch y := i.(type) { /*y=undef*/
@ -2313,27 +2334,27 @@ type Bad Bad // invalid type
conf := Config{Error: func(error) {}} conf := Config{Error: func(error) {}}
pkg, _ := conf.Check(f.PkgName.Value, []*syntax.File{f}, nil) pkg, _ := conf.Check(f.PkgName.Value, []*syntax.File{f}, nil)
scope := pkg.Scope() lookup := func(tname string) Type { return pkg.Scope().Lookup(tname).Type() }
var ( var (
EmptyIface = scope.Lookup("EmptyIface").Type().Underlying().(*Interface) EmptyIface = lookup("EmptyIface").Underlying().(*Interface)
I = scope.Lookup("I").Type().(*Named) I = lookup("I").(*Named)
II = I.Underlying().(*Interface) II = I.Underlying().(*Interface)
C = scope.Lookup("C").Type().(*Named) C = lookup("C").(*Named)
CI = C.Underlying().(*Interface) CI = C.Underlying().(*Interface)
Integer = scope.Lookup("Integer").Type().Underlying().(*Interface) Integer = lookup("Integer").Underlying().(*Interface)
EmptyTypeSet = scope.Lookup("EmptyTypeSet").Type().Underlying().(*Interface) EmptyTypeSet = lookup("EmptyTypeSet").Underlying().(*Interface)
N1 = scope.Lookup("N1").Type() N1 = lookup("N1")
N1p = NewPointer(N1) N1p = NewPointer(N1)
N2 = scope.Lookup("N2").Type() N2 = lookup("N2")
N2p = NewPointer(N2) N2p = NewPointer(N2)
N3 = scope.Lookup("N3").Type() N3 = lookup("N3")
N4 = scope.Lookup("N4").Type() N4 = lookup("N4")
Bad = scope.Lookup("Bad").Type() Bad = lookup("Bad")
) )
tests := []struct { tests := []struct {
t Type V Type
i *Interface T *Interface
want bool want bool
}{ }{
{I, II, true}, {I, II, true},
@ -2364,8 +2385,20 @@ type Bad Bad // invalid type
} }
for _, test := range tests { for _, test := range tests {
if got := Implements(test.t, test.i); got != test.want { if got := Implements(test.V, test.T); got != test.want {
t.Errorf("Implements(%s, %s) = %t, want %t", test.t, test.i, got, test.want) t.Errorf("Implements(%s, %s) = %t, want %t", test.V, test.T, got, test.want)
}
// The type assertion x.(T) is valid if T is an interface or if T implements the type of x.
// The assertion is never valid if T is a bad type.
V := test.T
T := test.V
want := false
if _, ok := T.Underlying().(*Interface); (ok || Implements(T, V)) && T != Bad {
want = true
}
if got := AssertableTo(V, T); got != want {
t.Errorf("AssertableTo(%s, %s) = %t, want %t", V, T, got, want)
} }
} }
} }

View File

@ -294,15 +294,14 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
return "(" + strings.Join(res, ", ") + ")" return "(" + strings.Join(res, ", ") + ")"
} }
func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) { func measure(x int, unit string) string {
measure := func(x int, unit string) string { if x != 1 {
s := fmt.Sprintf("%d %s", x, unit) unit += "s"
if x != 1 {
s += "s"
}
return s
} }
return fmt.Sprintf("%d %s", x, unit)
}
func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) {
vars := measure(nvars, "variable") vars := measure(nvars, "variable")
vals := measure(nvals, "value") vals := measure(nvals, "value")
rhs0 := rhs[0] rhs0 := rhs[0]

View File

@ -82,10 +82,24 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// of S and the respective parameter passing rules apply." // of S and the respective parameter passing rules apply."
S := x.typ S := x.typ
var T Type var T Type
if s, _ := structuralType(S).(*Slice); s != nil { if s, _ := coreType(S).(*Slice); s != nil {
T = s.elem T = s.elem
} else { } else {
check.errorf(x, invalidArg+"%s is not a slice", x) var cause string
switch {
case x.isNil():
cause = "have untyped nil"
case isTypeParam(S):
if u := coreType(S); u != nil {
cause = check.sprintf("%s has core type %s", x, u)
} else {
cause = check.sprintf("%s has no core type", x)
}
default:
cause = check.sprintf("have %s", x)
}
// don't use invalidArg prefix here as it would repeat "argument" in the error message
check.errorf(x, "first argument to append must be a slice; %s", cause)
return return
} }
@ -101,7 +115,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
if x.mode == invalid { if x.mode == invalid {
return return
} }
if t := structuralString(x.typ); t != nil && isString(t) { if t := coreString(x.typ); t != nil && isString(t) {
if check.Types != nil { if check.Types != nil {
sig := makeSig(S, S, x.typ) sig := makeSig(S, S, x.typ)
sig.variadic = true sig.variadic = true
@ -331,14 +345,14 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
case _Copy: case _Copy:
// copy(x, y []T) int // copy(x, y []T) int
dst, _ := structuralType(x.typ).(*Slice) dst, _ := coreType(x.typ).(*Slice)
var y operand var y operand
arg(&y, 1) arg(&y, 1)
if y.mode == invalid { if y.mode == invalid {
return return
} }
src0 := structuralString(y.typ) src0 := coreString(y.typ)
if src0 != nil && isString(src0) { if src0 != nil && isString(src0) {
src0 = NewSlice(universeByte) src0 = NewSlice(universeByte)
} }
@ -472,13 +486,13 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
} }
var min int // minimum number of arguments var min int // minimum number of arguments
switch structuralType(T).(type) { switch coreType(T).(type) {
case *Slice: case *Slice:
min = 2 min = 2
case *Map, *Chan: case *Map, *Chan:
min = 1 min = 1
case nil: case nil:
check.errorf(arg0, invalidArg+"cannot make %s: no structural type", arg0) check.errorf(arg0, invalidArg+"cannot make %s: no core type", arg0)
return return
default: default:
check.errorf(arg0, invalidArg+"cannot make %s; type must be slice, map, or channel", arg0) check.errorf(arg0, invalidArg+"cannot make %s; type must be slice, map, or channel", arg0)

View File

@ -168,7 +168,7 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
cgocall := x.mode == cgofunc cgocall := x.mode == cgofunc
// a type parameter may be "called" if all types have the same signature // a type parameter may be "called" if all types have the same signature
sig, _ := structuralType(x.typ).(*Signature) sig, _ := coreType(x.typ).(*Signature)
if sig == nil { if sig == nil {
check.errorf(x, invalidOp+"cannot call non-function %s", x) check.errorf(x, invalidOp+"cannot call non-function %s", x)
x.mode = invalid x.mode = invalid
@ -423,7 +423,7 @@ var cgoPrefixes = [...]string{
"_Cmacro_", // function to evaluate the expanded expression "_Cmacro_", // function to evaluate the expanded expression
} }
func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named) {
// these must be declared before the "goto Error" statements // these must be declared before the "goto Error" statements
var ( var (
obj Object obj Object
@ -525,7 +525,17 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
} }
check.exprOrType(x, e.X, false) check.exprOrType(x, e.X, false)
if x.mode == invalid { switch x.mode {
case typexpr:
// don't crash for "type T T.x" (was issue #51509)
if def != nil && x.typ == def {
check.cycleError([]Object{def.obj})
goto Error
}
case builtin:
check.errorf(e.Pos(), "cannot select on %s", x)
goto Error
case invalid:
goto Error goto Error
} }

View File

@ -18,19 +18,6 @@ var nopos syntax.Pos
// debugging/development support // debugging/development support
const debug = false // leave on during development const debug = false // leave on during development
// If forceStrict is set, the type-checker enforces additional
// rules not specified by the Go 1 spec, but which will
// catch guaranteed run-time errors if the respective
// code is executed. In other words, programs passing in
// strict mode are Go 1 compliant, but not all Go 1 programs
// will pass in strict mode. The additional rules are:
//
// - A type assertion x.(T) where T is an interface type
// is invalid if any (statically known) method that exists
// for both x and T have different signatures.
//
const forceStrict = false
// exprInfo stores information about an untyped expression. // exprInfo stores information about an untyped expression.
type exprInfo struct { type exprInfo struct {
isLhs bool // expression is lhs operand of a shift with delayed type-check isLhs bool // expression is lhs operand of a shift with delayed type-check
@ -139,7 +126,7 @@ type Checker struct {
untyped map[syntax.Expr]exprInfo // map of expressions without final type untyped map[syntax.Expr]exprInfo // map of expressions without final type
delayed []action // stack of delayed action segments; segments are processed in FIFO order 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) 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 // environment within which the current object is type-checked (valid only
// for the duration of type-checking a specific object) // for the duration of type-checking a specific object)
@ -218,6 +205,16 @@ func (check *Checker) pop() Object {
return obj 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. // NewChecker returns a new Checker instance for a given package.
// Package files may be added incrementally via checker.Files. // Package files may be added incrementally via checker.Files.
func NewChecker(conf *Config, pkg *Package, info *Info) *Checker { func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
@ -260,6 +257,8 @@ func (check *Checker) initFiles(files []*syntax.File) {
check.methods = nil check.methods = nil
check.untyped = nil check.untyped = nil
check.delayed = nil check.delayed = nil
check.objPath = nil
check.cleaners = nil
// determine package name and collect valid files // determine package name and collect valid files
pkg := check.pkg pkg := check.pkg
@ -328,8 +327,8 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
print("== processDelayed ==") print("== processDelayed ==")
check.processDelayed(0) // incl. all functions check.processDelayed(0) // incl. all functions
print("== expandDefTypes ==") print("== cleanup ==")
check.expandDefTypes() check.cleanup()
print("== initOrder ==") print("== initOrder ==")
check.initOrder() check.initOrder()
@ -357,7 +356,6 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
check.recvTParamMap = nil check.recvTParamMap = nil
check.brokenAliases = nil check.brokenAliases = nil
check.unionTypeSets = nil check.unionTypeSets = nil
check.defTypes = nil
check.ctxt = nil check.ctxt = nil
// TODO(gri) There's more memory we should release at this point. // TODO(gri) There's more memory we should release at this point.
@ -385,27 +383,13 @@ func (check *Checker) processDelayed(top int) {
check.delayed = check.delayed[:top] check.delayed = check.delayed[:top]
} }
func (check *Checker) expandDefTypes() { // cleanup runs cleanup for all collected cleaners.
// Ensure that every defined type created in the course of type-checking has func (check *Checker) cleanup() {
// either non-*Named underlying, or is unresolved. // Don't use a range clause since Named.cleanup may add more cleaners.
// for i := 0; i < len(check.cleaners); i++ {
// This guarantees that we don't leak any types whose underlying is *Named, check.cleaners[i].cleanup()
// 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
} }
check.cleaners = nil
} }
func (check *Checker) record(x *operand) { func (check *Checker) record(x *operand) {

View File

@ -19,12 +19,12 @@ func AsSignature(t Type) *Signature {
return u return u
} }
// If typ is a type parameter, structuralType returns the single underlying // If typ is a type parameter, CoreType returns the single underlying
// type of all types in the corresponding type constraint if it exists, or // type of all types in the corresponding type constraint if it exists, or
// nil otherwise. If the type set contains only unrestricted and restricted // nil otherwise. If the type set contains only unrestricted and restricted
// channel types (with identical element types), the single underlying type // channel types (with identical element types), the single underlying type
// is the restricted channel type if the restrictions are always the same. // is the restricted channel type if the restrictions are always the same.
// If typ is not a type parameter, structuralType returns the underlying type. // If typ is not a type parameter, CoreType returns the underlying type.
func StructuralType(t Type) Type { func CoreType(t Type) Type {
return structuralType(t) return coreType(t)
} }

View File

@ -49,11 +49,14 @@ func (check *Checker) conversion(x *operand, T Type) {
// have specific types, constant x cannot be // have specific types, constant x cannot be
// converted. // converted.
ok = T.(*TypeParam).underIs(func(u Type) bool { 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 { if u == nil {
cause = check.sprintf("%s does not contain specific types", T) cause = check.sprintf("%s does not contain specific types", T)
return false return false
} }
if isString(x.typ) && isBytesOrRunes(u) {
return true
}
if !constConvertibleTo(u, nil) { if !constConvertibleTo(u, nil) {
cause = check.sprintf("cannot convert %s to %s (in %s)", x, u, T) cause = check.sprintf("cannot convert %s to %s (in %s)", x, u, T)
return false return false

View File

@ -569,7 +569,6 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Fiel
// Keep track of bounds for later validation. // Keep track of bounds for later validation.
var bound Type var bound Type
var bounds []Type
for i, f := range list { for i, f := range list {
// Optimization: Re-use the previous type bound if it hasn't changed. // Optimization: Re-use the previous type bound if it hasn't changed.
// This also preserves the grouped output of type parameter lists // 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") check.error(f.Type, "cannot use a type parameter as constraint")
bound = Typ[Invalid] bound = Typ[Invalid]
} }
bounds = append(bounds, bound)
} }
tparams[i].bound = bound tparams[i].bound = bound
} }

View File

@ -124,6 +124,17 @@ func sprintf(qf Qualifier, debug bool, format string, args ...interface{}) strin
} }
buf.WriteByte(']') buf.WriteByte(']')
arg = buf.String() arg = buf.String()
case []*TypeParam:
var buf bytes.Buffer
buf.WriteByte('[')
for i, x := range a {
if i > 0 {
buf.WriteString(", ")
}
buf.WriteString(typeString(x, qf, debug)) // use typeString so we get subscripts when debugging
}
buf.WriteByte(']')
arg = buf.String()
} }
args[i] = arg args[i] = arg
} }

View File

@ -182,9 +182,9 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) {
return return
case syntax.Recv: case syntax.Recv:
u := structuralType(x.typ) u := coreType(x.typ)
if u == nil { if u == nil {
check.errorf(x, invalidOp+"cannot receive from %s: no structural type", x) check.errorf(x, invalidOp+"cannot receive from %s: no core type", x)
x.mode = invalid x.mode = invalid
return return
} }
@ -899,7 +899,7 @@ func (check *Checker) incomparableCause(typ Type) string {
} }
// see if we can extract a more specific error // see if we can extract a more specific error
var cause string 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...) cause = check.sprintf(format, args...)
}) })
return cause return cause
@ -1359,7 +1359,11 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
case hint != nil: case hint != nil:
// no composite literal type present - use hint (element type of enclosing type) // no composite literal type present - use hint (element type of enclosing type)
typ = hint typ = hint
base, _ = deref(structuralType(typ)) // *T implies &T{} 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: default:
// TODO(gri) provide better error messages depending on context // TODO(gri) provide better error messages depending on context
@ -1367,7 +1371,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
goto Error goto Error
} }
switch utyp := structuralType(base).(type) { switch utyp := coreType(base).(type) {
case *Struct: case *Struct:
// Prevent crash if the struct referred to is not yet set up. // Prevent crash if the struct referred to is not yet set up.
// See analogous comment for *Array. // See analogous comment for *Array.
@ -1552,7 +1556,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
return kind return kind
case *syntax.SelectorExpr: case *syntax.SelectorExpr:
check.selector(x, e) check.selector(x, e, nil)
case *syntax.IndexExpr: case *syntax.IndexExpr:
if check.indexExpr(x, e) { if check.indexExpr(x, e) {
@ -1638,6 +1642,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
case invalid: case invalid:
goto Error goto Error
case typexpr: case typexpr:
check.validVarType(e.X, x.typ)
x.typ = &Pointer{base: x.typ} x.typ = &Pointer{base: x.typ}
default: default:
var base Type var base Type

View File

@ -182,7 +182,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
} }
if !valid { if !valid {
check.errorf(x, invalidOp+"cannot index %s", x) check.errorf(e.Pos(), invalidOp+"cannot index %s", x)
x.mode = invalid x.mode = invalid
return false return false
} }
@ -213,9 +213,9 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
valid := false valid := false
length := int64(-1) // valid if >= 0 length := int64(-1) // valid if >= 0
switch u := structuralString(x.typ).(type) { switch u := coreString(x.typ).(type) {
case nil: case nil:
check.errorf(x, invalidOp+"cannot slice %s: %s has no structural type", x, x.typ) check.errorf(x, invalidOp+"cannot slice %s: %s has no core type", x, x.typ)
x.mode = invalid x.mode = invalid
return return

View File

@ -41,6 +41,13 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
}() }()
} }
if traceInference {
check.dump("-- inferA %s%s ➞ %s", tparams, params, targs)
defer func() {
check.dump("=> inferA %s ➞ %s", tparams, result)
}()
}
// There must be at least one type parameter, and no more type arguments than type parameters. // There must be at least one type parameter, and no more type arguments than type parameters.
n := len(tparams) n := len(tparams)
assert(n > 0 && len(targs) <= n) assert(n > 0 && len(targs) <= n)
@ -54,6 +61,64 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
} }
// len(targs) < n // len(targs) < n
const enableTparamRenaming = true
if enableTparamRenaming {
// For the purpose of type inference we must differentiate type parameters
// occurring in explicit type or value function arguments from the type
// parameters we are solving for via unification, because they may be the
// same in self-recursive calls. For example:
//
// func f[P *Q, Q any](p P, q Q) {
// f(p)
// }
//
// In this example, the fact that the P used in the instantation f[P] has
// the same pointer identity as the P we are trying to solve for via
// unification is coincidental: there is nothing special about recursive
// calls that should cause them to conflate the identity of type arguments
// with type parameters. To put it another way: any such self-recursive
// call is equivalent to a mutually recursive call, which does not run into
// any problems of type parameter identity. For example, the following code
// is equivalent to the code above.
//
// func f[P interface{*Q}, Q any](p P, q Q) {
// f2(p)
// }
//
// func f2[P interface{*Q}, Q any](p P, q Q) {
// f(p)
// }
//
// We can turn the first example into the second example by renaming type
// parameters in the original signature to give them a new identity. As an
// optimization, we do this only for self-recursive calls.
// We can detect if we are in a self-recursive call by comparing the
// identity of the first type parameter in the current function with the
// first type parameter in tparams. This works because type parameters are
// unique to their type parameter list.
selfRecursive := check.sig != nil && check.sig.tparams.Len() > 0 && tparams[0] == check.sig.tparams.At(0)
if selfRecursive {
// In self-recursive inference, rename the type parameters with new type
// parameters that are the same but for their pointer identity.
tparams2 := make([]*TypeParam, len(tparams))
for i, tparam := range tparams {
tname := NewTypeName(tparam.Obj().Pos(), tparam.Obj().Pkg(), tparam.Obj().Name(), nil)
tparams2[i] = NewTypeParam(tname, nil)
tparams2[i].index = tparam.index // == i
}
renameMap := makeRenameMap(tparams, tparams2)
for i, tparam := range tparams {
tparams2[i].bound = check.subst(pos, tparam.bound, renameMap, nil)
}
tparams = tparams2
params = check.subst(pos, params, renameMap, nil).(*Tuple)
}
}
// If we have more than 2 arguments, we may have arguments with named and unnamed types. // If we have more than 2 arguments, we may have arguments with named and unnamed types.
// If that is the case, permutate params and args such that the arguments with named // If that is the case, permutate params and args such that the arguments with named
// types are first in the list. This doesn't affect type inference if all types are taken // types are first in the list. This doesn't affect type inference if all types are taken
@ -403,6 +468,13 @@ func (w *tpWalker) isParameterizedTypeList(list []Type) bool {
func (check *Checker) inferB(pos syntax.Pos, tparams []*TypeParam, targs []Type) (types []Type, index int) { func (check *Checker) inferB(pos syntax.Pos, tparams []*TypeParam, targs []Type) (types []Type, index int) {
assert(len(tparams) >= len(targs) && len(targs) > 0) assert(len(tparams) >= len(targs) && len(targs) > 0)
if traceInference {
check.dump("-- inferB %s ➞ %s", tparams, targs)
defer func() {
check.dump("=> inferB %s ➞ %s", tparams, types)
}()
}
// Setup bidirectional unification between constraints // Setup bidirectional unification between constraints
// and the corresponding type arguments (which may be nil!). // and the corresponding type arguments (which may be nil!).
u := newUnifier(false) u := newUnifier(false)
@ -416,27 +488,88 @@ func (check *Checker) inferB(pos syntax.Pos, tparams []*TypeParam, targs []Type)
} }
} }
// If a constraint has a structural type, unify the corresponding type parameter with it. // Repeatedly apply constraint type inference as long as
for _, tpar := range tparams { // there are still unknown type arguments and progress is
sbound := structuralType(tpar) // being made.
if sbound != nil { //
// If the structural type is the underlying type of a single // This is an O(n^2) algorithm where n is the number of
// defined type in the constraint, use that defined type instead. // type parameters: if there is progress (and iteration
if named, _ := tpar.singleType().(*Named); named != nil { // continues), at least one type argument is inferred
sbound = named // per iteration and we have a doubly nested loop.
} // In practice this is not a problem because the number
if !u.unify(tpar, sbound) { // of type parameters tends to be very small (< 5 or so).
// TODO(gri) improve error message by providing the type arguments // (It should be possible for unification to efficiently
// which we know already // signal newly inferred type arguments; then the loops
check.errorf(pos, "%s does not match %s", tpar, sbound) // here could handle the respective type parameters only,
return nil, 0 // but that will come at a cost of extra complexity which
// may not be worth it.)
for n := u.x.unknowns(); n > 0; {
nn := n
for i, tpar := range tparams {
// If there is a core term (i.e., a core type with tilde information)
// unify the type parameter with the core type.
if core, single := coreTerm(tpar); core != nil {
// A type parameter can be unified with its core type in two cases.
tx := u.x.at(i)
switch {
case tx != nil:
// The corresponding type argument tx is known.
// In this case, if the core type has a tilde, the type argument's underlying
// type must match the core type, otherwise the type argument and the core type
// must match.
// If tx is an external type parameter, don't consider its underlying type
// (which is an interface). Core type unification will attempt to unify against
// core.typ.
// Note also that even with inexact unification we cannot leave away the under
// call here because it's possible that both tx and core.typ are named types,
// with under(tx) being a (named) basic type matching core.typ. Such cases do
// not match with inexact unification.
if core.tilde && !isTypeParam(tx) {
tx = under(tx)
}
if !u.unify(tx, core.typ) {
// TODO(gri) improve error message by providing the type arguments
// which we know already
// Don't use term.String() as it always qualifies types, even if they
// are in the current package.
tilde := ""
if core.tilde {
tilde = "~"
}
check.errorf(pos, "%s does not match %s%s", tpar, tilde, core.typ)
return nil, 0
}
case single && !core.tilde:
// The corresponding type argument tx is unknown and there's a single
// specific type and no tilde.
// In this case the type argument must be that single type; set it.
u.x.set(i, core.typ)
default:
// Unification is not possible and no progress was made.
continue
}
// The number of known type arguments may have changed.
nn = u.x.unknowns()
if nn == 0 {
break // all type arguments are known
}
} }
} }
assert(nn <= n)
if nn == n {
break // no progress
}
n = nn
} }
// u.x.types() now contains the incoming type arguments plus any additional type // u.x.types() now contains the incoming type arguments plus any additional type
// arguments which were inferred from structural types. The newly inferred non- // arguments which were inferred from core terms. The newly inferred non-nil
// nil entries may still contain references to other type parameters. // entries may still contain references to other type parameters.
// For instance, for [A any, B interface{ []C }, C interface{ *A }], if A == int // For instance, for [A any, B interface{ []C }, C interface{ *A }], if A == int
// was given, unification produced the type list [int, []C, *A]. We eliminate the // was given, unification produced the type list [int, []C, *A]. We eliminate the
// remaining type parameters by substituting the type parameters in this type list // remaining type parameters by substituting the type parameters in this type list
@ -504,8 +637,8 @@ func (check *Checker) inferB(pos syntax.Pos, tparams []*TypeParam, targs []Type)
} }
// Once nothing changes anymore, we may still have type parameters left; // Once nothing changes anymore, we may still have type parameters left;
// e.g., a structural constraint *P may match a type parameter Q but we // e.g., a constraint with core type *P may match a type parameter Q but
// don't have any type arguments to fill in for *P or Q (issue #45548). // we don't have any type arguments to fill in for *P or Q (issue #45548).
// Don't let such inferences escape, instead nil them out. // Don't let such inferences escape, instead nil them out.
for i, typ := range types { for i, typ := range types {
if typ != nil && isParameterized(tparams, typ) { if typ != nil && isParameterized(tparams, typ) {
@ -525,6 +658,42 @@ func (check *Checker) inferB(pos syntax.Pos, tparams []*TypeParam, targs []Type)
return return
} }
// If the type parameter has a single specific type S, coreTerm returns (S, true).
// Otherwise, if tpar has a core type T, it returns a term corresponding to that
// core type and false. In that case, if any term of tpar has a tilde, the core
// term has a tilde. In all other cases coreTerm returns (nil, false).
func coreTerm(tpar *TypeParam) (*term, bool) {
n := 0
var single *term // valid if n == 1
var tilde bool
tpar.is(func(t *term) bool {
if t == nil {
assert(n == 0)
return false // no terms
}
n++
single = t
if t.tilde {
tilde = true
}
return true
})
if n == 1 {
if debug {
assert(debug && under(single.typ) == coreType(tpar))
}
return single, true
}
if typ := coreType(tpar); typ != nil {
// A core type is always an underlying type.
// If any term of tpar has a tilde, we don't
// have a precise core type and we must return
// a tilde as well.
return &term{tilde, typ}, false
}
return nil, false
}
type cycleFinder struct { type cycleFinder struct {
tparams []*TypeParam tparams []*TypeParam
types []Type types []Type
@ -570,8 +739,6 @@ func (w *cycleFinder) typ(typ Type) {
// in signatures where they are handled explicitly. // in signatures where they are handled explicitly.
case *Signature: case *Signature:
// There are no "method types" so we should never see a recv.
assert(t.recv == nil)
if t.params != nil { if t.params != nil {
w.varList(t.params.vars) w.varList(t.params.vars)
} }

View File

@ -15,10 +15,10 @@ import (
// Instantiate instantiates the type orig with the given type arguments targs. // Instantiate instantiates the type orig with the given type arguments targs.
// orig must be a *Named or a *Signature type. If there is no error, the // orig must be a *Named or a *Signature type. If there is no error, the
// resulting Type is a new, instantiated (not parameterized) type of the same // resulting Type is an instantiated type of the same kind (either a *Named or
// kind (either a *Named or a *Signature). Methods attached to a *Named type // a *Signature). Methods attached to a *Named type are also instantiated, and
// are also instantiated, and associated with a new *Func that has the same // associated with a new *Func that has the same position as the original
// position as the original method, but nil function scope. // method, but nil function scope.
// //
// If ctxt is non-nil, it may be used to de-duplicate the instance against // If ctxt is non-nil, it may be used to de-duplicate the instance against
// previous instances with the same identity. As a special case, generic // previous instances with the same identity. As a special case, generic
@ -204,7 +204,7 @@ func (check *Checker) implements(V, T Type) error {
// If T is comparable, V must be comparable. // 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. // Remember as a pending error and report only if we don't have a more specific error.
var pending 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) pending = errorf("%s does not implement comparable", V)
} }

View File

@ -37,7 +37,7 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
} }
// set method receivers if necessary // set method receivers if necessary
typ := new(Interface) typ := (*Checker)(nil).newInterface()
for _, m := range methods { for _, m := range methods {
if sig := m.typ.(*Signature); sig.recv == nil { if sig := m.typ.(*Signature); sig.recv == nil {
sig.recv = NewVar(m.pos, m.pkg, "", typ) sig.recv = NewVar(m.pos, m.pkg, "", typ)
@ -54,6 +54,15 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
return typ 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 // MarkImplicit marks the interface t as implicit, meaning this interface
// corresponds to a constraint literal such as ~T or A|B without explicit // corresponds to a constraint literal such as ~T or A|B without explicit
// interface embedding. MarkImplicit should be called before any concurrent use // interface embedding. MarkImplicit should be called before any concurrent use
@ -100,6 +109,11 @@ func (t *Interface) String() string { return TypeString(t, nil) }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Implementation // Implementation
func (t *Interface) cleanup() {
t.check = nil
t.embedPos = nil
}
func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType, def *Named) { func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType, def *Named) {
addEmbedded := func(pos syntax.Pos, typ Type) { addEmbedded := func(pos syntax.Pos, typ Type) {
ityp.embeddeds = append(ityp.embeddeds, typ) 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) // (don't sort embeddeds: they must correspond to *embedPos entries)
sortMethods(ityp.methods) sortMethods(ityp.methods)
// Compute type set with a non-nil *Checker as soon as possible // Compute type set as soon as possible to report any errors.
// to report any errors. Subsequent uses of type sets will use // Subsequent uses of type sets will use this computed type
// this computed type set and won't need to pass in a *Checker. // 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
check.later(func() { check.later(func() {
computeInterfaceTypeSet(check, iface.Pos(), ityp) computeInterfaceTypeSet(check, iface.Pos(), ityp)
ityp.check = nil
}).describef(iface, "compute type set for %s", ityp) }).describef(iface, "compute type set for %s", ityp)
} }

View File

@ -66,12 +66,13 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
obj, index, indirect = lookupFieldOrMethod(T, addressable, pkg, name, false) obj, index, indirect = lookupFieldOrMethod(T, addressable, pkg, name, false)
// If we didn't find anything and if we have a type parameter with a structural constraint, // If we didn't find anything and if we have a type parameter with a core type,
// see if there is a matching field (but not a method, those need to be declared explicitly // see if there is a matching field (but not a method, those need to be declared
// in the constraint). If the structural constraint is a named pointer type (see above), we // explicitly in the constraint). If the constraint is a named pointer type (see
// are ok here because only fields are accepted as results. // above), we are ok here because only fields are accepted as results.
if obj == nil && isTypeParam(T) { const enableTParamFieldLookup = false // see issue #51576
if t := structuralType(T); t != nil { if enableTParamFieldLookup && obj == nil && isTypeParam(T) {
if t := coreType(T); t != nil {
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false) obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false)
if _, ok := obj.(*Var); !ok { if _, ok := obj.(*Var); !ok {
obj, index, indirect = nil, nil, false // accept fields (variables) only obj, index, indirect = nil, nil, false // accept fields (variables) only
@ -425,18 +426,31 @@ func (check *Checker) funcString(f *Func) string {
// method required by V and whether it is missing or just has the wrong type. // method required by V and whether it is missing or just has the wrong type.
// The receiver may be nil if assertableTo is invoked through an exported API call // The receiver may be nil if assertableTo is invoked through an exported API call
// (such as AssertableTo), i.e., when all methods have been type-checked. // (such as AssertableTo), i.e., when all methods have been type-checked.
// If the global constant forceStrict is set, assertions that are known to fail // TODO(gri) replace calls to this function with calls to newAssertableTo.
// are not permitted.
func (check *Checker) assertableTo(V *Interface, T Type) (method, wrongType *Func) { func (check *Checker) assertableTo(V *Interface, T Type) (method, wrongType *Func) {
// no static check is required if T is an interface // no static check is required if T is an interface
// spec: "If T is an interface type, x.(T) asserts that the // spec: "If T is an interface type, x.(T) asserts that the
// dynamic type of x implements the interface T." // dynamic type of x implements the interface T."
if IsInterface(T) && !forceStrict { if IsInterface(T) {
return return
} }
// TODO(gri) fix this for generalized interfaces
return check.missingMethod(T, V, false) return check.missingMethod(T, V, false)
} }
// newAssertableTo reports whether a value of type V can be asserted to have type T.
// It also implements behavior for interfaces that currently are only permitted
// in constraint position (we have not yet defined that behavior in the spec).
func (check *Checker) newAssertableTo(V *Interface, T Type) error {
// no static check is required if T is an interface
// spec: "If T is an interface type, x.(T) asserts that the
// dynamic type of x implements the interface T."
if IsInterface(T) {
return nil
}
return check.implements(T, V)
}
// deref dereferences typ if it is a *Pointer and returns its base and true. // deref dereferences typ if it is a *Pointer and returns its base and true.
// Otherwise it returns (typ, false). // Otherwise it returns (typ, false).
func deref(typ Type) (Type, bool) { func deref(typ Type) (Type, bool) {

View File

@ -72,16 +72,36 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar
} }
// Ensure that typ is always expanded and sanity-checked. // Ensure that typ is always expanded and sanity-checked.
if check != nil { if check != nil {
check.defTypes = append(check.defTypes, typ) check.needsCleanup(typ)
} }
return 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 // 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. // instantiated types, this is same as the type name of the origin type.
func (t *Named) Obj() *TypeName { return t.orig.obj } // for non-instances this is the same as t.obj func (t *Named) Obj() *TypeName { return t.orig.obj } // for non-instances this is the same as t.obj
// Origin returns the parameterized type from which the named type t is // Origin returns the generic type from which the named type t is
// instantiated. If t is not an instantiated type, the result is t. // instantiated. If t is not an instantiated type, the result is t.
func (t *Named) Origin() *Named { return t.orig } func (t *Named) Origin() *Named { return t.orig }
@ -89,7 +109,7 @@ func (t *Named) Origin() *Named { return t.orig }
// between parameterized instantiated and non-instantiated types. // between parameterized instantiated and non-instantiated types.
// TypeParams returns the type parameters of the named type t, or nil. // TypeParams returns the type parameters of the named type t, or nil.
// The result is non-nil for an (originally) parameterized type even if it is instantiated. // The result is non-nil for an (originally) generic type even if it is instantiated.
func (t *Named) TypeParams() *TypeParamList { return t.resolve(nil).tparams } func (t *Named) TypeParams() *TypeParamList { return t.resolve(nil).tparams }
// SetTypeParams sets the type parameters of the named type t. // SetTypeParams sets the type parameters of the named type t.
@ -102,7 +122,11 @@ func (t *Named) SetTypeParams(tparams []*TypeParam) {
// TypeArgs returns the type arguments used to instantiate the named type t. // TypeArgs returns the type arguments used to instantiate the named type t.
func (t *Named) TypeArgs() *TypeList { return t.targs } func (t *Named) TypeArgs() *TypeList { return t.targs }
// NumMethods returns the number of explicit methods whose receiver is named type t. // NumMethods returns the number of explicit methods defined for t.
//
// For an ordinary or instantiated type t, the receiver base type of these
// methods will be the named type t. For an uninstantiated generic type t, each
// method receiver will be instantiated with its receiver type parameters.
func (t *Named) NumMethods() int { return t.resolve(nil).methods.Len() } func (t *Named) NumMethods() int { return t.resolve(nil).methods.Len() }
// Method returns the i'th method of named type t for 0 <= i < t.NumMethods(). // Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
@ -360,11 +384,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 // that it wasn't substituted. In this case we need to create a new
// *Interface before modifying receivers. // *Interface before modifying receivers.
if iface == n.orig.underlying { if iface == n.orig.underlying {
iface = &Interface{ old := iface
embeddeds: iface.embeddeds, iface = check.newInterface()
complete: iface.complete, iface.embeddeds = old.embeddeds
implicit: iface.implicit, // should be false but be conservative iface.complete = old.complete
} iface.implicit = old.implicit // should be false but be conservative
underlying = iface underlying = iface
} }
iface.methods = methods iface.methods = methods

View File

@ -31,7 +31,7 @@ func isBasic(t Type, info BasicInfo) bool {
// The allX predicates below report whether t is an X. // The allX predicates below report whether t is an X.
// If t is a type parameter the result is true if isX is true // If t is a type parameter the result is true if isX is true
// for all specified types of the type parameter's type set. // for all specified types of the type parameter's type set.
// allX is an optimized version of isX(structuralType(t)) (which // allX is an optimized version of isX(coreType(t)) (which
// is the same as underIs(t, isX)). // is the same as underIs(t, isX)).
func allBoolean(t Type) bool { return allBasic(t, IsBoolean) } func allBoolean(t Type) bool { return allBasic(t, IsBoolean) }
@ -45,7 +45,7 @@ func allNumericOrString(t Type) bool { return allBasic(t, IsNumeric|IsString) }
// allBasic reports whether under(t) is a basic type with the specified info. // allBasic reports whether under(t) is a basic type with the specified info.
// If t is a type parameter, the result is true if isBasic(t, info) is true // If t is a type parameter, the result is true if isBasic(t, info) is true
// for all specific types of the type parameter's type set. // for all specific types of the type parameter's type set.
// allBasic(t, info) is an optimized version of isBasic(structuralType(t), info). // allBasic(t, info) is an optimized version of isBasic(coreType(t), info).
func allBasic(t Type, info BasicInfo) bool { func allBasic(t Type, info BasicInfo) bool {
if tpar, _ := t.(*TypeParam); tpar != nil { if tpar, _ := t.(*TypeParam); tpar != nil {
return tpar.is(func(t *term) bool { return t != nil && isBasic(t.typ, info) }) return tpar.is(func(t *term) bool { return t != nil && isBasic(t.typ, info) })
@ -102,11 +102,12 @@ func isGeneric(t Type) bool {
// Comparable reports whether values of type T are comparable. // Comparable reports whether values of type T are comparable.
func Comparable(T Type) bool { 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. // 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] { if seen[T] {
return true return true
} }
@ -124,7 +125,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
return true return true
case *Struct: case *Struct:
for _, f := range t.fields { for _, f := range t.fields {
if !comparable(f.typ, seen, nil) { if !comparable(f.typ, dynamic, seen, nil) {
if reportf != nil { if reportf != nil {
reportf("struct containing %s cannot be compared", f.typ) 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 return true
case *Array: case *Array:
if !comparable(t.elem, seen, nil) { if !comparable(t.elem, dynamic, seen, nil) {
if reportf != nil { if reportf != nil {
reportf("%s cannot be compared", t) reportf("%s cannot be compared", t)
} }
@ -141,7 +142,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
} }
return true return true
case *Interface: case *Interface:
return !isTypeParam(T) || t.typeSet().IsComparable(seen) return dynamic && !isTypeParam(T) || t.typeSet().IsComparable(seen)
} }
return false return false
} }

View File

@ -413,7 +413,7 @@ func (check *Checker) collectObjects() {
case *syntax.TypeDecl: case *syntax.TypeDecl:
if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) { if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) {
check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later") check.versionErrorf(s.TParamList[0], "go1.18", "type parameter")
} }
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil) obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil)
check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s}) check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s})
@ -458,7 +458,7 @@ func (check *Checker) collectObjects() {
check.recordDef(s.Name, obj) check.recordDef(s.Name, obj)
} }
if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) && !hasTParamError { if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) && !hasTParamError {
check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later") check.versionErrorf(s.TParamList[0], "go1.18", "type parameter")
} }
info := &declInfo{file: fileScope, fdecl: s} info := &declInfo{file: fileScope, fdecl: s}
// Methods are not package-level objects but we still track them in the // Methods are not package-level objects but we still track them in the

View File

@ -116,11 +116,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
// lookup in the scope. // lookup in the scope.
for i, p := range rparams { for i, p := range rparams {
if p.Value == "_" { if p.Value == "_" {
tpar := sig.rparams.At(i)
if check.recvTParamMap == nil { if check.recvTParamMap == nil {
check.recvTParamMap = make(map[*syntax.Name]*TypeParam) check.recvTParamMap = make(map[*syntax.Name]*TypeParam)
} }
check.recvTParamMap[p] = tpar check.recvTParamMap[p] = tparams[i]
} }
} }
// determine receiver type to get its type parameters // 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 // provide type parameter bounds
// - only do this if we have the right number (otherwise an error is reported elsewhere) if len(tparams) == len(recvTParams) {
if sig.RecvTypeParams().Len() == len(recvTParams) { smap := makeRenameMap(recvTParams, tparams)
// We have a list of *TypeNames but we need a list of Types. for i, tpar := range tparams {
list := make([]Type, sig.RecvTypeParams().Len()) recvTPar := recvTParams[i]
for i, t := range sig.RecvTypeParams().list() { check.mono.recordCanon(tpar, recvTPar)
list[i] = t // recvTPar.bound is (possibly) parameterized in the context of the
check.mono.recordCanon(t, recvTParams[i]) // receiver type declaration. Substitute parameters for the current
} // context.
smap := makeSubstMap(recvTParams, list) tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil)
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)
} }
} 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: case 1:
recv = recvList[0] recv = recvList[0]
} }
sig.recv = recv
// TODO(gri) We should delay rtyp expansion to when we actually need the // Delay validation of receiver type as it may cause premature expansion
// receiver; thus all checks here should be delayed to later. // of types the receiver type is dependent on (see issues #51232, #51233).
rtyp, _ := deref(recv.typ) 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." // 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) // (ignore invalid types - error was reported before)
if rtyp != Typ[Invalid] { if rtyp != Typ[Invalid] {
var err string var err string
switch T := rtyp.(type) { switch T := rtyp.(type) {
case *Named: case *Named:
T.resolve(check.bestContext(nil)) T.resolve(check.bestContext(nil))
// The receiver type may be an instantiated type referred to // The receiver type may be an instantiated type referred to
// by an alias (which cannot have receiver parameters for now). // by an alias (which cannot have receiver parameters for now).
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil { if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ) check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
break break
} }
// spec: "The type denoted by T is called the receiver base type; it must not // 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 // be a pointer or interface type and it must be declared in the same package
// as the method." // as the method."
if T.obj.pkg != check.pkg { if T.obj.pkg != check.pkg {
err = "type not defined in this package" 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 { if check.conf.CompilerErrorMessages {
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ) check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
err = "" err = ""
} }
} else { default:
// The underlying type of a receiver base type can be a type parameter; check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
// 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
})
} }
case *Basic: if err != "" {
err = "basic or unnamed type" check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
if check.conf.CompilerErrorMessages {
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
err = ""
} }
default:
check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
} }
if err != "" { }).describef(recv, "validate receiver %s", recv)
check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
// ok to continue
}
}
sig.recv = recv
} }
sig.params = NewTuple(params...) sig.params = NewTuple(params...)

View File

@ -409,9 +409,9 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
if ch.mode == invalid || val.mode == invalid { if ch.mode == invalid || val.mode == invalid {
return return
} }
u := structuralType(ch.typ) u := coreType(ch.typ)
if u == nil { if u == nil {
check.errorf(s, invalidOp+"cannot send to %s: no structural type", &ch) check.errorf(s, invalidOp+"cannot send to %s: no core type", &ch)
return return
} }
uch, _ := u.(*Chan) uch, _ := u.(*Chan)
@ -626,14 +626,15 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
case *syntax.ForStmt: case *syntax.ForStmt:
inner |= breakOk | continueOk inner |= breakOk | continueOk
check.openScope(s, "for")
defer check.closeScope()
if rclause, _ := s.Init.(*syntax.RangeClause); rclause != nil { if rclause, _ := s.Init.(*syntax.RangeClause); rclause != nil {
check.rangeStmt(inner, s, rclause) check.rangeStmt(inner, s, rclause)
break break
} }
check.openScope(s, "for")
defer check.closeScope()
check.simpleStmt(s.Init) check.simpleStmt(s.Init)
if s.Cond != nil { if s.Cond != nil {
var x operand var x operand
@ -809,8 +810,6 @@ func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, gu
} }
func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *syntax.RangeClause) { func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *syntax.RangeClause) {
// scope already opened
// determine lhs, if any // determine lhs, if any
sKey := rclause.Lhs // possibly nil sKey := rclause.Lhs // possibly nil
var sValue, sExtra syntax.Expr var sValue, sExtra syntax.Expr
@ -835,9 +834,9 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
// determine key/value types // determine key/value types
var key, val Type var key, val Type
if x.mode != invalid { if x.mode != invalid {
// Ranging over a type parameter is permitted if it has a structural type. // Ranging over a type parameter is permitted if it has a core type.
var cause string var cause string
u := structuralType(x.typ) u := coreType(x.typ)
if t, _ := u.(*Chan); t != nil { if t, _ := u.(*Chan); t != nil {
if sValue != nil { if sValue != nil {
check.softErrorf(sValue, "range over %s permits only one iteration variable", &x) check.softErrorf(sValue, "range over %s permits only one iteration variable", &x)
@ -852,7 +851,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
// ok to continue // ok to continue
} }
if u == nil { if u == nil {
cause = check.sprintf("%s has no structural type", x.typ) cause = check.sprintf("%s has no core type", x.typ)
} }
} }
key, val = rangeKeyVal(u) key, val = rangeKeyVal(u)
@ -866,6 +865,11 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
} }
} }
// Open the for-statement block scope now, after the range clause.
// Iteration variables declared with := need to go in this scope (was issue #51437).
check.openScope(s, "range")
defer check.closeScope()
// check assignment to/declaration of iteration variables // check assignment to/declaration of iteration variables
// (irregular assignment, cannot easily map to existing assignment checks) // (irregular assignment, cannot easily map to existing assignment checks)
@ -874,9 +878,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
rhs := [2]Type{key, val} // key, val may be nil rhs := [2]Type{key, val} // key, val may be nil
if rclause.Def { if rclause.Def {
// short variable declaration; variable scope starts after the range clause // short variable declaration
// (the for loop opens a new scope, so variables on the lhs never redeclare
// previously declared variables)
var vars []*Var var vars []*Var
for i, lhs := range lhs { for i, lhs := range lhs {
if lhs == nil { if lhs == nil {
@ -913,12 +915,8 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
// declare variables // declare variables
if len(vars) > 0 { if len(vars) > 0 {
scopePos := syntax.EndPos(rclause.X) // TODO(gri) should this just be s.Body.Pos (spec clarification)? scopePos := s.Body.Pos()
for _, obj := range vars { for _, obj := range vars {
// spec: "The scope of a constant or variable identifier declared inside
// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
// for short variable declarations) and ends at the end of the innermost
// containing block."
check.declare(check.scope, nil /* recordDef already called */, obj, scopePos) check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
} }
} else { } else {

View File

@ -21,6 +21,17 @@ func makeSubstMap(tpars []*TypeParam, targs []Type) substMap {
return proj return proj
} }
// makeRenameMap is like makeSubstMap, but creates a map used to rename type
// parameters in from with the type parameters in to.
func makeRenameMap(from, to []*TypeParam) substMap {
assert(len(from) == len(to))
proj := make(substMap, len(from))
for i, tpar := range from {
proj[tpar] = to[i]
}
return proj
}
func (m substMap) empty() bool { func (m substMap) empty() bool {
return len(m) == 0 return len(m) == 0
} }
@ -149,7 +160,10 @@ func (subst *subster) typ(typ Type) Type {
methods, mcopied := subst.funcList(t.methods) methods, mcopied := subst.funcList(t.methods)
embeddeds, ecopied := subst.typeList(t.embeddeds) embeddeds, ecopied := subst.typeList(t.embeddeds)
if mcopied || ecopied { 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 // If we've changed the interface type, we may need to replace its
// receiver if the receiver type is the original interface. Receivers of // receiver if the receiver type is the original interface. Receivers of
// *Named type are replaced during named type expansion. // *Named type are replaced during named type expansion.

View File

@ -92,15 +92,6 @@ func (xl termlist) norm() termlist {
return rl 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. // union returns the union xl yl.
func (xl termlist) union(yl termlist) termlist { func (xl termlist) union(yl termlist) termlist {
return append(xl, yl...).norm() return append(xl, yl...).norm()

View File

@ -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) { func TestTermlistUnion(t *testing.T) {
for _, test := range []struct { for _, test := range []struct {
xl, yl, want string xl, yl, want string

View File

@ -148,7 +148,7 @@ func _[
_ = make /* ERROR expects 2 or 3 arguments */ (S1) _ = make /* ERROR expects 2 or 3 arguments */ (S1)
_ = make(S1, 10, 20) _ = make(S1, 10, 20)
_ = make /* ERROR expects 2 or 3 arguments */ (S1, 10, 20, 30) _ = make /* ERROR expects 2 or 3 arguments */ (S1, 10, 20, 30)
_ = make(S2 /* ERROR cannot make S2: no structural type */ , 10) _ = make(S2 /* ERROR cannot make S2: no core type */ , 10)
type M0 map[string]int type M0 map[string]int
_ = make(map[string]int) _ = make(map[string]int)
@ -156,7 +156,7 @@ func _[
_ = make(M1) _ = make(M1)
_ = make(M1, 10) _ = make(M1, 10)
_ = make/* ERROR expects 1 or 2 arguments */(M1, 10, 20) _ = make/* ERROR expects 1 or 2 arguments */(M1, 10, 20)
_ = make(M2 /* ERROR cannot make M2: no structural type */ ) _ = make(M2 /* ERROR cannot make M2: no core type */ )
type C0 chan int type C0 chan int
_ = make(chan int) _ = make(chan int)
@ -164,7 +164,7 @@ func _[
_ = make(C1) _ = make(C1)
_ = make(C1, 10) _ = make(C1, 10)
_ = make/* ERROR expects 1 or 2 arguments */(C1, 10, 20) _ = make/* ERROR expects 1 or 2 arguments */(C1, 10, 20)
_ = make(C2 /* ERROR cannot make C2: no structural type */ ) _ = make(C2 /* ERROR cannot make C2: no core type */ )
_ = make(C3) _ = make(C3)
} }

View File

@ -15,9 +15,9 @@ func append1() {
var x int var x int
var s []byte var s []byte
_ = append() // ERROR not enough arguments _ = append() // ERROR not enough arguments
_ = append("foo" /* ERROR not a slice */ ) _ = append("foo" /* ERROR must be a slice */ )
_ = append(nil /* ERROR not a slice */ , s) _ = append(nil /* ERROR must be a slice */ , s)
_ = append(x /* ERROR not a slice */ , s) _ = append(x /* ERROR must be a slice */ , s)
_ = append(s) _ = append(s)
_ = append(s, nil...) _ = append(s, nil...)
append /* ERROR not used */ (s) append /* ERROR not used */ (s)
@ -77,7 +77,7 @@ func append3() {
_ = append(f2()) _ = append(f2())
_ = append(f3()) _ = append(f3())
_ = append(f5()) _ = append(f5())
_ = append(ff /* ERROR not a slice */ ()) // TODO(gri) better error message _ = append(ff /* ERROR must be a slice */ ()) // TODO(gri) better error message
} }
func cap1() { func cap1() {

View File

@ -8,21 +8,21 @@ import "strconv"
type any interface{} type any interface{}
func f0[A any, B interface{~*C}, C interface{~*D}, D interface{~*A}](A, B, C, D) {} func f0[A any, B interface{*C}, C interface{*D}, D interface{*A}](A, B, C, D) {}
func _() { func _() {
f := f0[string] f := f0[string]
f("a", nil, nil, nil) f("a", nil, nil, nil)
f0("a", nil, nil, nil) f0("a", nil, nil, nil)
} }
func f1[A any, B interface{~*A}](A, B) {} func f1[A any, B interface{*A}](A, B) {}
func _() { func _() {
f := f1[int] f := f1[int]
f(int(0), new(int)) f(int(0), new(int))
f1(int(0), new(int)) f1(int(0), new(int))
} }
func f2[A any, B interface{~[]A}](A, B) {} func f2[A any, B interface{[]A}](A, B) {}
func _() { func _() {
f := f2[byte] f := f2[byte]
f(byte(0), []byte{}) f(byte(0), []byte{})
@ -38,7 +38,7 @@ func _() {
// f3(x, &x, &x) // f3(x, &x, &x)
// } // }
func f4[A any, B interface{~[]C}, C interface{~*A}](A, B, C) {} func f4[A any, B interface{[]C}, C interface{*A}](A, B, C) {}
func _() { func _() {
f := f4[int] f := f4[int]
var x int var x int
@ -46,7 +46,7 @@ func _() {
f4(x, []*int{}, &x) f4(x, []*int{}, &x)
} }
func f5[A interface{~struct{b B; c C}}, B any, C interface{~*B}](x B) A { panic(0) } func f5[A interface{struct{b B; c C}}, B any, C interface{*B}](x B) A { panic(0) }
func _() { func _() {
x := f5(1.2) x := f5(1.2)
var _ float64 = x.b var _ float64 = x.b
@ -79,14 +79,14 @@ var _ = Double(MySlice{1})
type Setter[B any] interface { type Setter[B any] interface {
Set(string) Set(string)
~*B *B
} }
func FromStrings[T interface{}, PT Setter[T]](s []string) []T { func FromStrings[T interface{}, PT Setter[T]](s []string) []T {
result := make([]T, len(s)) result := make([]T, len(s))
for i, v := range s { for i, v := range s {
// The type of &result[i] is *T which is in the type list // The type of &result[i] is *T which is in the type list
// of Setter2, so we can convert it to PT. // of Setter, so we can convert it to PT.
p := PT(&result[i]) p := PT(&result[i])
// PT has a Set method. // PT has a Set method.
p.Set(v) p.Set(v)

View File

@ -4,44 +4,46 @@
package typeInference package typeInference
// As of issue #51527, type-type inference has been disabled.
// basic inference // basic inference
type Tb[P ~*Q, Q any] int type Tb[P ~*Q, Q any] int
func _() { func _() {
var x Tb[*int] var x Tb /* ERROR got 1 arguments */ [*int]
var y Tb[*int, int] var y Tb[*int, int]
x = y x = y /* ERROR cannot use y .* in assignment */
_ = x _ = x
} }
// recursive inference // recursive inference
type Tr[A any, B ~*C, C ~*D, D ~*A] int type Tr[A any, B *C, C *D, D *A] int
func _() { func _() {
var x Tr[string] var x Tr /* ERROR got 1 arguments */ [string]
var y Tr[string, ***string, **string, *string] var y Tr[string, ***string, **string, *string]
var z Tr[int, ***int, **int, *int] var z Tr[int, ***int, **int, *int]
x = y x = y /* ERROR cannot use y .* in assignment */
x = z // ERROR cannot use z .* as Tr x = z // ERROR cannot use z .* as Tr
_ = x _ = x
} }
// other patterns of inference // other patterns of inference
type To0[A any, B ~[]A] int type To0[A any, B []A] int
type To1[A any, B ~struct{a A}] int type To1[A any, B struct{a A}] int
type To2[A any, B ~[][]A] int type To2[A any, B [][]A] int
type To3[A any, B ~[3]*A] int type To3[A any, B [3]*A] int
type To4[A any, B any, C ~struct{a A; b B}] int type To4[A any, B any, C struct{a A; b B}] int
func _() { func _() {
var _ To0[int] var _ To0 /* ERROR got 1 arguments */ [int]
var _ To1[int] var _ To1 /* ERROR got 1 arguments */ [int]
var _ To2[int] var _ To2 /* ERROR got 1 arguments */ [int]
var _ To3[int] var _ To3 /* ERROR got 1 arguments */ [int]
var _ To4[int, string] var _ To4 /* ERROR got 2 arguments */ [int, string]
} }
// failed inference // failed inference
type Tf0[A, B any] int type Tf0[A, B any] int
type Tf1[A any, B ~struct{a A; c C}, C any] int type Tf1[A any, B ~struct{a A; c C}, C any] int
func _() { func _() {
var _ Tf0 /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [int] var _ Tf0 /* ERROR got 1 arguments but 2 type parameters */ [int]
var _ Tf1 /* ERROR cannot infer B */ /* ERROR got 1 arguments but 3 type parameters */ [int] var _ Tf1 /* ERROR got 1 arguments but 3 type parameters */ [int]
} }

View File

@ -134,11 +134,11 @@ func _[T interface{ ~string }] (x T, i, j, k int) { var _ T = x[i:j:k /* ERROR 3
type myByte1 []byte type myByte1 []byte
type myByte2 []byte type myByte2 []byte
func _[T interface{ []byte | myByte1 | myByte2 }] (x T, i, j, k int) { var _ T = x[i:j:k] } func _[T interface{ []byte | myByte1 | myByte2 }] (x T, i, j, k int) { var _ T = x[i:j:k] }
func _[T interface{ []byte | myByte1 | []int }] (x T, i, j, k int) { var _ T = x[ /* ERROR no structural type */ i:j:k] } func _[T interface{ []byte | myByte1 | []int }] (x T, i, j, k int) { var _ T = x[ /* ERROR no core type */ i:j:k] }
func _[T interface{ []byte | myByte1 | myByte2 | string }] (x T, i, j, k int) { var _ T = x[i:j] } func _[T interface{ []byte | myByte1 | myByte2 | string }] (x T, i, j, k int) { var _ T = x[i:j] }
func _[T interface{ []byte | myByte1 | myByte2 | string }] (x T, i, j, k int) { var _ T = x[i:j:k /* ERROR 3-index slice of string */ ] } func _[T interface{ []byte | myByte1 | myByte2 | string }] (x T, i, j, k int) { var _ T = x[i:j:k /* ERROR 3-index slice of string */ ] }
func _[T interface{ []byte | myByte1 | []int | string }] (x T, i, j, k int) { var _ T = x[ /* ERROR no structural type */ i:j] } func _[T interface{ []byte | myByte1 | []int | string }] (x T, i, j, k int) { var _ T = x[ /* ERROR no core type */ i:j] }
// len/cap built-ins // len/cap built-ins
@ -230,7 +230,7 @@ func _[
for _, _ = range s1 {} for _, _ = range s1 {}
var s2 S2 var s2 S2
for range s2 /* ERROR cannot range over s2.*no structural type */ {} for range s2 /* ERROR cannot range over s2.*no core type */ {}
var a0 []int var a0 []int
for range a0 {} for range a0 {}
@ -243,7 +243,7 @@ func _[
for _, _ = range a1 {} for _, _ = range a1 {}
var a2 A2 var a2 A2
for range a2 /* ERROR cannot range over a2.*no structural type */ {} for range a2 /* ERROR cannot range over a2.*no core type */ {}
var p0 *[10]int var p0 *[10]int
for range p0 {} for range p0 {}
@ -256,7 +256,7 @@ func _[
for _, _ = range p1 {} for _, _ = range p1 {}
var p2 P2 var p2 P2
for range p2 /* ERROR cannot range over p2.*no structural type */ {} for range p2 /* ERROR cannot range over p2.*no core type */ {}
var m0 map[string]int var m0 map[string]int
for range m0 {} for range m0 {}
@ -269,7 +269,7 @@ func _[
for _, _ = range m1 {} for _, _ = range m1 {}
var m2 M2 var m2 M2
for range m2 /* ERROR cannot range over m2.*no structural type */ {} for range m2 /* ERROR cannot range over m2.*no core type */ {}
} }
// type inference checks // type inference checks

View File

@ -78,7 +78,7 @@ func _() {
related1(si, "foo" /* ERROR cannot use "foo" */ ) related1(si, "foo" /* ERROR cannot use "foo" */ )
} }
func related2[Elem any, Slice interface{~[]Elem}](e Elem, s Slice) {} func related2[Elem any, Slice interface{[]Elem}](e Elem, s Slice) {}
func _() { func _() {
// related2 can be called with explicit instantiation. // related2 can be called with explicit instantiation.
@ -109,16 +109,8 @@ func _() {
related3[int, []int]() related3[int, []int]()
related3[byte, List[byte]]() related3[byte, List[byte]]()
// Alternatively, the 2nd type argument can be inferred // The 2nd type argument cannot be inferred from the first
// from the first one through constraint type inference. // one because there's two possible choices: []Elem and
related3[int]() // List[Elem].
related3[int]( /* ERROR cannot infer Slice */ )
// The inferred type is the structural type of the Slice
// type parameter.
var _ []int = related3[int]()
// It is not the defined parameterized type List.
type anotherList []float32
var _ anotherList = related3[float32]() // valid
var _ anotherList = related3 /* ERROR cannot use .* \(value of type List\[float32\]\) as anotherList */ [float32, List[float32]]()
} }

View File

@ -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 // 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 // and it shadows the predeclared identifier int which then cannot be used
// anymore as expected. // 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., // and usually should be avoided. There are some notable exceptions; e.g.,
// sometimes it makes sense to use the identifier "copy" which happens to // sometimes it makes sense to use the identifier "copy" which happens to
// also be the name of a predeclared built-in function. // also be the name of a predeclared built-in function.

View File

@ -292,7 +292,7 @@ func _[T interface{~int|~float64}]() {
// It is possible to create composite literals of type parameter // It is possible to create composite literals of type parameter
// type as long as it's possible to create a composite literal // type as long as it's possible to create a composite literal
// of the structural type of the type parameter's constraint. // of the core type of the type parameter's constraint.
func _[P interface{ ~[]int }]() P { func _[P interface{ ~[]int }]() P {
return P{} return P{}
return P{1, 2, 3} return P{1, 2, 3}
@ -307,7 +307,7 @@ func _[P interface{ ~[]E }, E interface{ map[string]P } ]() P {
} }
// This is a degenerate case with a singleton type set, but we can create // This is a degenerate case with a singleton type set, but we can create
// composite literals even if the structural type is a defined type. // composite literals even if the core type is a defined type.
type MyInts []int type MyInts []int
func _[P MyInts]() P { func _[P MyInts]() P {

View File

@ -35,7 +35,7 @@ func _() int {
return deref(p) return deref(p)
} }
func addrOfCopy[V any, P ~*V](v V) P { func addrOfCopy[V any, P *V](v V) P {
return &v return &v
} }

View File

@ -47,7 +47,7 @@ type _ struct{
} }
type _ struct{ type _ struct{
I3 // ERROR interface is .* comparable I3 // ERROR interface contains type constraints
} }
// General composite types. // General composite types.
@ -59,19 +59,19 @@ type (
_ []I1 // ERROR interface is .* comparable _ []I1 // ERROR interface is .* comparable
_ []I2 // ERROR interface contains type constraints _ []I2 // ERROR interface contains type constraints
_ *I3 // ERROR interface is .* comparable _ *I3 // ERROR interface contains type constraints
_ map[I1 /* ERROR interface is .* comparable */ ]I2 // ERROR interface contains type constraints _ map[I1 /* ERROR interface is .* comparable */ ]I2 // ERROR interface contains type constraints
_ chan I3 // ERROR interface is .* comparable _ chan I3 // ERROR interface contains type constraints
_ func(I1 /* ERROR interface is .* comparable */ ) _ func(I1 /* ERROR interface is .* comparable */ )
_ func() I2 // ERROR interface contains type constraints _ func() I2 // ERROR interface contains type constraints
) )
// Other cases. // Other cases.
var _ = [...]I3 /* ERROR interface is .* comparable */ {} var _ = [...]I3 /* ERROR interface contains type constraints */ {}
func _(x interface{}) { func _(x interface{}) {
_ = x.(I3 /* ERROR interface is .* comparable */ ) _ = x.(I3 /* ERROR interface contains type constraints */ )
} }
type T1[_ any] struct{} type T1[_ any] struct{}

View File

@ -9,7 +9,7 @@ const L = 10
type ( type (
_ [L]struct{} _ [L]struct{}
_ [A /* ERROR undeclared name A for array length */ ]struct{} _ [A /* ERROR undeclared name A for array length */ ]struct{}
_ [B /* ERROR not an expression */ ]struct{} _ [B /* ERROR invalid array length B */ ]struct{}
_[A any] struct{} _[A any] struct{}
B int B int

View File

@ -12,7 +12,7 @@ type C4 interface{ chan int | chan<- int }
type C5[T any] interface{ ~chan T | <-chan T } type C5[T any] interface{ ~chan T | <-chan T }
func _[T any](ch T) { func _[T any](ch T) {
<-ch // ERROR cannot receive from ch .* no structural type <-ch // ERROR cannot receive from ch .* no core type
} }
func _[T C0](ch T) { func _[T C0](ch T) {
@ -28,7 +28,7 @@ func _[T C2](ch T) {
} }
func _[T C3](ch T) { func _[T C3](ch T) {
<-ch // ERROR cannot receive from ch .* no structural type <-ch // ERROR cannot receive from ch .* no core type
} }
func _[T C4](ch T) { func _[T C4](ch T) {

View File

@ -4,7 +4,7 @@
package p package p
func f[F interface{~*Q}, G interface{~*R}, Q, R any](q Q, r R) {} func f[F interface{*Q}, G interface{*R}, Q, R any](q Q, r R) {}
func _() { func _() {
f[*float64, *int](1, 2) f[*float64, *int](1, 2)

View File

@ -12,7 +12,7 @@ type C4 interface{ chan int | chan<- int }
type C5[T any] interface{ ~chan T | chan<- T } type C5[T any] interface{ ~chan T | chan<- T }
func _[T any](ch T) { func _[T any](ch T) {
ch /* ERROR cannot send to ch .* no structural type */ <- 0 ch /* ERROR cannot send to ch .* no core type */ <- 0
} }
func _[T C0](ch T) { func _[T C0](ch T) {
@ -28,7 +28,7 @@ func _[T C2](ch T) {
} }
func _[T C3](ch T) { func _[T C3](ch T) {
ch /* ERROR cannot send to ch .* no structural type */ <- 0 ch /* ERROR cannot send to ch .* no core type */ <- 0
} }
func _[T C4](ch T) { func _[T C4](ch T) {

View File

@ -8,13 +8,13 @@
package go1_17 package go1_17
type T[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ] struct{} type T[P /* ERROR type parameter requires go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ] struct{}
// for init (and main, but we're not in package main) we should only get one error // for init (and main, but we're not in package main) we should only get one error
func init[P /* ERROR func init must have no type parameters */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {} func init[P /* ERROR func init must have no type parameters */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {}
func main[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {} func main[P /* ERROR type parameter requires go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {}
func f[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ](x P) { func f[P /* ERROR type parameter requires go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ](x P) {
var _ T[ /* ERROR type instantiation requires go1\.18 or later */ int] var _ T[ /* ERROR type instantiation requires go1\.18 or later */ int]
var _ (T[ /* ERROR type instantiation requires go1\.18 or later */ int]) var _ (T[ /* ERROR type instantiation requires go1\.18 or later */ int])
_ = T[ /* ERROR type instantiation requires go1\.18 or later */ int]{} _ = T[ /* ERROR type instantiation requires go1\.18 or later */ int]{}

View File

@ -2,24 +2,19 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// This issue is still open:
// - the error messages could be better or are incorrect
// - unification fails due to stack overflow that is caught
package p package p
func f[P any](a, _ P) { func f[P any](a, _ P) {
var x int var x int
// TODO(gri) these error messages, while correct, could be better // TODO(gri) these error messages, while correct, could be better
f(a, x /* ERROR type int of x does not match P */) f(a, x /* ERROR type int of x does not match inferred type P for P */)
f(x, a /* ERROR type P of a does not match inferred type int for P */) f(x, a /* ERROR type P of a does not match inferred type int for P */)
} }
func g[P any](a, b P) { func g[P any](a, b P) {
g(a, b) g(a, b)
// TODO(gri) these error messages are incorrect because the code is valid g(&a, &b)
g(&a, & /* ERROR type \*P of &b does not match inferred type \*P for P */ b) g([]P{}, []P{})
g([]P{}, [ /* ERROR type \[\]P of \[\]P{} does not match inferred type \[\]P for P */ ]P{})
// work-around: provide type argument explicitly // work-around: provide type argument explicitly
g[*P](&a, &b) g[*P](&a, &b)

View File

@ -2,14 +2,12 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// This issue is still open:
// - the error messages are unclear
// - unification fails due to stack overflow that is caught
package p package p
func f[P *Q, Q any](P, Q) { func f[P *Q, Q any](P, Q) {
// TODO(gri) these error messages are unclear _ = f[P]
_ = f[ /* ERROR P does not match \*Q */ P] }
_ = f[ /* ERROR cannot infer P */ *P]
func f2[P /* ERROR instantiation cycle */ *Q, Q any](P, Q) {
_ = f2[*P]
} }

View File

@ -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.
// This file is tested when running "go test -run Manual"
// without source arguments. Use for one-off debugging.
package p
// The following is OK, per the special handling for type literals discussed in issue #49482.
type _[P *struct{}] struct{}
type _[P *int,] int
type _[P (*int),] int
const P = 2 // declare P to avoid noisy 'undeclared name' errors below.
// The following parse as invalid array types.
type _[P *int /* ERROR "int \(type\) is not an expression" */ ] int
type _[P /* ERROR non-function P */ (*int)] int
// The following should be parsed as a generic type, but is instead parsed as an array type.
type _[P *struct /* ERROR "not an expression" */ {}| int /* ERROR "not an expression" */ ] struct{}
// The following fails to parse, due to the '~'
type _[P *struct /* ERROR "not an expression" */ {}|~ /* ERROR "unexpected ~" */ int] struct{}

View File

@ -10,9 +10,10 @@ type S[A, B any] struct {
func (S[A, B]) m() {} func (S[A, B]) m() {}
// TODO(gri) We should only report one error below. See issue #50588. // TODO(gri): with type-type inference enabled we should only report one error
// below. See issue #50588.
func _[A any](s S /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [A]) { func _[A any](s S /* ERROR got 1 arguments but 2 type parameters */ [A]) {
// we should see no follow-on errors below // we should see no follow-on errors below
s.f = 1 s.f = 1
s.m() s.m()
@ -21,7 +22,7 @@ func _[A any](s S /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type
// another test case from the issue // another test case from the issue
func _() { func _() {
X(Interface[*F /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [string]](Impl{})) X(Interface[*F /* ERROR got 1 arguments but 2 type parameters */ [string]](Impl{}))
} }
func X[Q Qer](fs Interface[Q]) { func X[Q Qer](fs Interface[Q]) {

View File

@ -0,0 +1,11 @@
// 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 _[P1 any, P2 ~byte](s1 P1, s2 P2) {
_ = append(nil /* ERROR first argument to append must be a slice; have untyped nil */ , 0)
_ = append(s1 /* ERROR s1 .* has no core type */ , 0)
_ = append(s2 /* ERROR s2 .* has core type byte */ , 0)
}

View File

@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Field accesses through type parameters are disabled
// until we have a more thorough understanding of the
// implications on the spec. See issue #51576.
package p package p
type Sf struct { type Sf struct {
@ -9,13 +13,13 @@ type Sf struct {
} }
func f0[P Sf](p P) { func f0[P Sf](p P) {
_ = p.f _ = p.f // ERROR p\.f undefined
p.f = 0 p.f /* ERROR p\.f undefined */ = 0
} }
func f0t[P ~struct{f int}](p P) { func f0t[P ~struct{f int}](p P) {
_ = p.f _ = p.f // ERROR p\.f undefined
p.f = 0 p.f /* ERROR p\.f undefined */ = 0
} }
var _ = f0[Sf] var _ = f0[Sf]
@ -25,8 +29,8 @@ var _ = f0[Sm /* ERROR does not implement */ ]
var _ = f0t[Sm /* ERROR does not implement */ ] var _ = f0t[Sm /* ERROR does not implement */ ]
func f1[P interface{ Sf; m() }](p P) { func f1[P interface{ Sf; m() }](p P) {
_ = p.f _ = p.f // ERROR p\.f undefined
p.f = 0 p.f /* ERROR p\.f undefined */ = 0
p.m() p.m()
} }
@ -44,20 +48,20 @@ type Sfm struct {
func (Sfm) m() {} func (Sfm) m() {}
func f2[P interface{ Sfm; m() }](p P) { func f2[P interface{ Sfm; m() }](p P) {
_ = p.f _ = p.f // ERROR p\.f undefined
p.f = 0 p.f /* ERROR p\.f undefined */ = 0
p.m() p.m()
} }
var _ = f2[Sfm] var _ = f2[Sfm]
// special case: structural type is a named pointer type // special case: core type is a named pointer type
type PSfm *Sfm type PSfm *Sfm
func f3[P interface{ PSfm }](p P) { func f3[P interface{ PSfm }](p P) {
_ = p.f _ = p.f // ERROR p\.f undefined
p.f = 0 p.f /* ERROR p\.f undefined */ = 0
p.m /* ERROR type P has no field or method m */ () p.m /* ERROR type P has no field or method m */ ()
} }

View File

@ -0,0 +1,47 @@
// 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
// The core type of M2 unifies with the type of m1
// during function argument type inference.
// M2's constraint is unnamed.
func f1[K1 comparable, E1 any](m1 map[K1]E1) {}
func f2[M2 map[string]int](m2 M2) {
f1(m2)
}
// The core type of M3 unifies with the type of m1
// during function argument type inference.
// M3's constraint is named.
type Map3 map[string]int
func f3[M3 Map3](m3 M3) {
f1(m3)
}
// The core type of M5 unifies with the core type of M4
// during constraint type inference.
func f4[M4 map[K4]int, K4 comparable](m4 M4) {}
func f5[M5 map[K5]int, K5 comparable](m5 M5) {
f4(m5)
}
// test case from issue
func Copy[MC ~map[KC]VC, KC comparable, VC any](dst, src MC) {
for k, v := range src {
dst[k] = v
}
}
func Merge[MM ~map[KM]VM, KM comparable, VM any](ms ...MM) MM {
result := MM{}
for _, m := range ms {
Copy(result, m)
}
return result
}

View File

@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Field accesses through type parameters are disabled
// until we have a more thorough understanding of the
// implications on the spec. See issue #51576.
package p package p
// The first example from the issue. // The first example from the issue.
@ -18,9 +22,12 @@ type numericAbs[T Numeric] interface {
// AbsDifference computes the absolute value of the difference of // AbsDifference computes the absolute value of the difference of
// a and b, where the absolute value is determined by the Abs method. // a and b, where the absolute value is determined by the Abs method.
func absDifference[T numericAbs[T /* ERROR T does not implement Numeric */]](a, b T) T { func absDifference[T numericAbs[T /* ERROR T does not implement Numeric */]](a, b T) T {
// TODO: the error below should probably be positioned on the '-'. // Field accesses are not permitted for now. Keep an error so
d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value // we can find and fix this code once the situation changes.
return d.Abs() return a.Value // ERROR a\.Value undefined
// TODO: The error below should probably be positioned on the '-'.
// d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value
// return d.Abs()
} }
// The second example from the issue. // The second example from the issue.

View File

@ -16,7 +16,7 @@ func G[A, B any](F[A, B]) {
func _() { func _() {
// TODO(gri) only report one error below (issue #50932) // TODO(gri) only report one error below (issue #50932)
var x F /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [int] var x F /* ERROR got 1 arguments but 2 type parameters */ [int]
G(x /* ERROR does not match */) G(x /* ERROR does not match */)
} }
@ -46,9 +46,9 @@ func NSG[G any](c RSC[G]) {
fmt.Println(c) fmt.Println(c)
} }
func MMD[Rc RC /* ERROR cannot infer RG */ /* ERROR got 1 arguments */ [RG], RG any, G any]() M /* ERROR got 2 arguments */ /* ERROR Rc does not match */ [Rc, RG] { func MMD[Rc RC /* ERROR got 1 arguments */ [RG], RG any, G any]() M /* ERROR got 2 arguments */ [Rc, RG] {
var nFn NFn /* ERROR got 2 arguments */ /* ERROR Rc does not match */ [Rc, RG] var nFn NFn /* ERROR got 2 arguments */ [Rc, RG]
var empty Rc var empty Rc
switch any(empty).(type) { switch any(empty).(type) {

View File

@ -0,0 +1,18 @@
// 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 "fmt"
type (
_ [fmt /* ERROR invalid array length fmt */ ]int
_ [float64 /* ERROR invalid array length float64 */ ]int
_ [f /* ERROR invalid array length f */ ]int
_ [nil /* ERROR invalid array length nil */ ]int
)
func f()
var _ fmt.Stringer // use fmt

View File

@ -0,0 +1,18 @@
// 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 checking the following code should not cause an infinite recursion.
func f[M map[K]int, K comparable](m M) {
f(m)
}
// Equivalent code using mutual recursion.
func f1[M map[K]int, K comparable](m M) {
f2(m)
}
func f2[M map[K]int, K comparable](m M) {
f1(m)
}

View File

@ -0,0 +1,164 @@
// 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
// Constraint type inference should be independent of the
// ordering of the type parameter declarations. Try all
// permutations in the test case below.
// Permutations produced by https://go.dev/play/p/PHcZNGJTEBZ.
func f00[S1 ~[]E1, S2 ~[]E2, E1 ~byte, E2 ~byte](S1, S2) {}
func f01[S2 ~[]E2, S1 ~[]E1, E1 ~byte, E2 ~byte](S1, S2) {}
func f02[E1 ~byte, S1 ~[]E1, S2 ~[]E2, E2 ~byte](S1, S2) {}
func f03[S1 ~[]E1, E1 ~byte, S2 ~[]E2, E2 ~byte](S1, S2) {}
func f04[S2 ~[]E2, E1 ~byte, S1 ~[]E1, E2 ~byte](S1, S2) {}
func f05[E1 ~byte, S2 ~[]E2, S1 ~[]E1, E2 ~byte](S1, S2) {}
func f06[E2 ~byte, S2 ~[]E2, S1 ~[]E1, E1 ~byte](S1, S2) {}
func f07[S2 ~[]E2, E2 ~byte, S1 ~[]E1, E1 ~byte](S1, S2) {}
func f08[S1 ~[]E1, E2 ~byte, S2 ~[]E2, E1 ~byte](S1, S2) {}
func f09[E2 ~byte, S1 ~[]E1, S2 ~[]E2, E1 ~byte](S1, S2) {}
func f10[S2 ~[]E2, S1 ~[]E1, E2 ~byte, E1 ~byte](S1, S2) {}
func f11[S1 ~[]E1, S2 ~[]E2, E2 ~byte, E1 ~byte](S1, S2) {}
func f12[S1 ~[]E1, E1 ~byte, E2 ~byte, S2 ~[]E2](S1, S2) {}
func f13[E1 ~byte, S1 ~[]E1, E2 ~byte, S2 ~[]E2](S1, S2) {}
func f14[E2 ~byte, S1 ~[]E1, E1 ~byte, S2 ~[]E2](S1, S2) {}
func f15[S1 ~[]E1, E2 ~byte, E1 ~byte, S2 ~[]E2](S1, S2) {}
func f16[E1 ~byte, E2 ~byte, S1 ~[]E1, S2 ~[]E2](S1, S2) {}
func f17[E2 ~byte, E1 ~byte, S1 ~[]E1, S2 ~[]E2](S1, S2) {}
func f18[E2 ~byte, E1 ~byte, S2 ~[]E2, S1 ~[]E1](S1, S2) {}
func f19[E1 ~byte, E2 ~byte, S2 ~[]E2, S1 ~[]E1](S1, S2) {}
func f20[S2 ~[]E2, E2 ~byte, E1 ~byte, S1 ~[]E1](S1, S2) {}
func f21[E2 ~byte, S2 ~[]E2, E1 ~byte, S1 ~[]E1](S1, S2) {}
func f22[E1 ~byte, S2 ~[]E2, E2 ~byte, S1 ~[]E1](S1, S2) {}
func f23[S2 ~[]E2, E1 ~byte, E2 ~byte, S1 ~[]E1](S1, S2) {}
type myByte byte
func _(a []byte, b []myByte) {
f00(a, b)
f01(a, b)
f02(a, b)
f03(a, b)
f04(a, b)
f05(a, b)
f06(a, b)
f07(a, b)
f08(a, b)
f09(a, b)
f10(a, b)
f11(a, b)
f12(a, b)
f13(a, b)
f14(a, b)
f15(a, b)
f16(a, b)
f17(a, b)
f18(a, b)
f19(a, b)
f20(a, b)
f21(a, b)
f22(a, b)
f23(a, b)
}
// Constraint type inference may have to iterate.
// Again, the order of the type parameters shouldn't matter.
func g0[S ~[]E, M ~map[string]S, E any](m M) {}
func g1[M ~map[string]S, S ~[]E, E any](m M) {}
func g2[E any, S ~[]E, M ~map[string]S](m M) {}
func g3[S ~[]E, E any, M ~map[string]S](m M) {}
func g4[M ~map[string]S, E any, S ~[]E](m M) {}
func g5[E any, M ~map[string]S, S ~[]E](m M) {}
func _(m map[string][]byte) {
g0(m)
g1(m)
g2(m)
g3(m)
g4(m)
g5(m)
}
// Worst-case scenario.
// There are 10 unknown type parameters. In each iteration of
// constraint type inference we infer one more, from right to left.
// Each iteration looks repeatedly at all 11 type parameters,
// requiring a total of 10*11 = 110 iterations with the current
// implementation. Pathological case.
func h[K any, J ~*K, I ~*J, H ~*I, G ~*H, F ~*G, E ~*F, D ~*E, C ~*D, B ~*C, A ~*B](x A) {}
func _(x **********int) {
h(x)
}
// Examples with channel constraints and tilde.
func ch1[P chan<- int]() (_ P) { return } // core(P) == chan<- int (single type, no tilde)
func ch2[P ~chan int]() { return } // core(P) == ~chan<- int (tilde)
func ch3[P chan E, E any](E) { return } // core(P) == chan<- E (single type, no tilde)
func ch4[P chan E | ~chan<- E, E any](E) { return } // core(P) == ~chan<- E (tilde)
func ch5[P chan int | chan<- int]() { return } // core(P) == chan<- int (not a single type)
func _() {
// P can be inferred as there's a single specific type and no tilde.
var _ chan int = ch1 /* ERROR cannot use ch1.*value of type chan<- int */ ()
var _ chan<- int = ch1()
// P cannot be inferred as there's a tilde.
ch2( /* ERROR cannot infer P */ )
type myChan chan int
ch2[myChan]()
// P can be inferred as there's a single specific type and no tilde.
var e int
ch3(e)
// P cannot be inferred as there's more than one specific type and a tilde.
ch4( /* ERROR cannot infer P */ e)
_ = ch4[chan int]
// P cannot be inferred as there's more than one specific type.
ch5( /* ERROR cannot infer P */ )
ch5[chan<- int]()
}
// test case from issue
func equal[M1 ~map[K1]V1, M2 ~map[K2]V2, K1, K2 ~uint32, V1, V2 ~string](m1 M1, m2 M2) bool {
if len(m1) != len(m2) {
return false
}
for k, v1 := range m1 {
if v2, ok := m2[K2(k)]; !ok || V2(v1) != v2 {
return false
}
}
return true
}
func equalFixed[K1, K2 ~uint32, V1, V2 ~string](m1 map[K1]V1, m2 map[K2]V2) bool {
if len(m1) != len(m2) {
return false
}
for k, v1 := range m1 {
if v2, ok := m2[K2(k)]; !ok || v1 != V1(v2) {
return false
}
}
return true
}
type (
someNumericID uint32
someStringID string
)
func _() {
foo := map[uint32]string{10: "bar"}
bar := map[someNumericID]someStringID{10: "bar"}
equal(foo, bar)
}

View File

@ -0,0 +1,30 @@
// 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 /* ERROR got 1 arguments */ [RCT]
}
type concreteF[RCT RC[RG], RG any] struct {
makeFn func() Fn /* ERROR got 1 arguments */ [RCT]
}
func (c *concreteF[RCT, RG]) Fn() Fn /* ERROR got 1 arguments */ [RCT] {
return c.makeFn()
}
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F /* ERROR got 1 arguments */ [RCT] {
// TODO(rfindley): eliminate the duplicate error below.
return & /* ERROR cannot use .* as F\[RCT\] */ concreteF /* ERROR got 1 arguments */ [RCT]{
makeFn: nil,
}
}

View File

@ -0,0 +1,27 @@
// 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
// As of issue #51527, type-type inference has been disabled.
type RC[RG any] interface {
~[]RG
}
type Fn[RCT RC[RG], RG any] func(RCT)
type FFn[RCT RC[RG], RG any] func() Fn /* ERROR got 1 arguments */ [RCT]
type F[RCT RC[RG], RG any] interface {
Fn() Fn /* ERROR got 1 arguments */ [RCT]
}
type concreteF[RCT RC[RG], RG any] struct {
makeFn FFn /* ERROR got 1 arguments */ [RCT]
}
func (c *concreteF[RCT, RG]) Fn() Fn /* ERROR got 1 arguments */ [RCT] {
return c.makeFn()
}

View File

@ -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},
})
}

View File

@ -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 */ }}
}

View File

@ -0,0 +1,18 @@
// 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() {}
// TODO(rfindley): eliminate the duplicate errors here.
func (T /* ERROR got 1 type parameter, but receiver base type declares 2 */ /* ERROR got 1 arguments but 2 type parameters */ [_]) m1() {}
func (T[_, _]) m2() {}
// TODO(gri) this error is unfortunate (issue #51343)
func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {}

View File

@ -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 */
}

View File

@ -0,0 +1,24 @@
// 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 Map map[string]int
func f[M ~map[K]V, K comparable, V any](M) {}
func g[M map[K]V, K comparable, V any](M) {}
func _[M1 ~map[K]V, M2 map[K]V, K comparable, V any]() {
var m1 M1
f(m1)
g( /* ERROR M1 does not implement map\[K\]V */ m1) // M1 has tilde
var m2 M2
f(m2)
g(m2) // M1 does not have tilde
var m3 Map
f(m3)
g( /* ERROR Map does not implement map\[string\]int */ m3) // M in g does not have tilde
}

View File

@ -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("")
}

View File

@ -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 T struct{}
func (T) m() []int { return nil }
func f(x T) {
for _, x := range func() []int {
return x.m() // x declared in parameter list of f
}() {
_ = x // x declared by range clause
}
}

View File

@ -0,0 +1,54 @@
// 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 _[T comparable](x T) {
_ = x == x
}
func _[T interface{interface{comparable}}](x T) {
_ = x == x
}
func _[T interface{comparable; interface{comparable}}](x T) {
_ = x == x
}
func _[T interface{comparable; ~int}](x T) {
_ = x == x
}
func _[T interface{comparable; ~[]byte}](x T) {
_ = x /* ERROR cannot compare */ == x
}
// TODO(gri) The error message here should be better. See issue #51525.
func _[T interface{comparable; ~int; ~string}](x T) {
_ = x /* ERROR cannot compare */ == x
}
// TODO(gri) The error message here should be better. See issue #51525.
func _[T interface{~int; ~string}](x T) {
_ = x /* ERROR cannot compare */ == x
}
func _[T interface{comparable; interface{~int}; interface{int|float64}}](x T) {
_ = x == x
}
func _[T interface{interface{comparable; ~int}; interface{~float64; comparable; m()}}](x T) {
_ = x /* ERROR cannot compare */ == x
}
// test case from issue
func f[T interface{comparable; []byte|string}](x T) {
_ = x == x
}
func _(s []byte) {
f( /* ERROR \[\]byte does not implement interface{comparable; \[\]byte\|string} */ s)
_ = f[[ /* ERROR does not implement */ ]byte]
}

View File

@ -0,0 +1,7 @@
// 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 T /* ERROR illegal cycle */ T.x

View File

@ -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
var _ = (*interface /* ERROR interface contains type constraints */ {int})(nil)
// abbreviated test case from issue
type TypeSet interface{ int | string }
func _() {
f((*TypeSet /* ERROR interface contains type constraints */)(nil))
}
func f(any) {}

View File

@ -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 f[P interface{ m(R) }, R any]() {}
type T = interface { m(int) }
func _() {
_ = f[ /* ERROR cannot infer R */ T] // don't crash in type inference
}

View File

@ -7,9 +7,7 @@ package types2
// A Type represents a type of Go. // A Type represents a type of Go.
// All types implement the Type interface. // All types implement the Type interface.
type Type interface { type Type interface {
// Underlying returns the underlying type of a type // Underlying returns the underlying type of a type.
// w/o following forwarding chains. Only used by
// client packages.
Underlying() Type Underlying() Type
// String returns a string representation of a type. // String returns a string representation of a type.
@ -27,13 +25,13 @@ func under(t Type) Type {
return t.Underlying() return t.Underlying()
} }
// If t is not a type parameter, structuralType returns the underlying type. // If t is not a type parameter, coreType returns the underlying type.
// If t is a type parameter, structuralType returns the single underlying // If t is a type parameter, coreType returns the single underlying
// type of all types in its type set if it exists, or nil otherwise. If the // type of all types in its type set if it exists, or nil otherwise. If the
// type set contains only unrestricted and restricted channel types (with // type set contains only unrestricted and restricted channel types (with
// identical element types), the single underlying type is the restricted // identical element types), the single underlying type is the restricted
// channel type if the restrictions are always the same, or nil otherwise. // channel type if the restrictions are always the same, or nil otherwise.
func structuralType(t Type) Type { func coreType(t Type) Type {
tpar, _ := t.(*TypeParam) tpar, _ := t.(*TypeParam)
if tpar == nil { if tpar == nil {
return under(t) return under(t)
@ -59,10 +57,10 @@ func structuralType(t Type) Type {
return nil return nil
} }
// structuralString is like structuralType but also considers []byte // coreString is like coreType but also considers []byte
// and strings as identical. In this case, if successful and we saw // and strings as identical. In this case, if successful and we saw
// a string, the result is of type (possibly untyped) string. // a string, the result is of type (possibly untyped) string.
func structuralString(t Type) Type { func coreString(t Type) Type {
tpar, _ := t.(*TypeParam) tpar, _ := t.(*TypeParam)
if tpar == nil { if tpar == nil {
return under(t) // string or untyped string return under(t) // string or untyped string

View File

@ -31,11 +31,13 @@ func (t *TypeParam) Obj() *TypeName { return t.obj }
// or Signature type by calling SetTypeParams. Setting a type parameter on more // or Signature type by calling SetTypeParams. Setting a type parameter on more
// than one type will result in a panic. // than one type will result in a panic.
// //
// The constraint argument can be nil, and set later via SetConstraint. // The constraint argument can be nil, and set later via SetConstraint. If the
// constraint is non-nil, it must be fully defined.
func NewTypeParam(obj *TypeName, constraint Type) *TypeParam { func NewTypeParam(obj *TypeName, constraint Type) *TypeParam {
return (*Checker)(nil).newTypeParam(obj, constraint) return (*Checker)(nil).newTypeParam(obj, constraint)
} }
// check may be nil
func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam { func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
// Always increment lastID, even if it is not used. // Always increment lastID, even if it is not used.
id := nextID() id := nextID()
@ -50,9 +52,7 @@ func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
// iface may mutate typ.bound, so we must ensure that iface() is called // iface may mutate typ.bound, so we must ensure that iface() is called
// at least once before the resulting TypeParam escapes. // at least once before the resulting TypeParam escapes.
if check != nil { if check != nil {
check.later(func() { check.needsCleanup(typ)
typ.iface()
})
} else if constraint != nil { } else if constraint != nil {
typ.iface() typ.iface()
} }
@ -72,8 +72,10 @@ func (t *TypeParam) Constraint() Type {
// SetConstraint sets the type constraint for t. // SetConstraint sets the type constraint for t.
// //
// SetConstraint should not be called concurrently, but once SetConstraint // It must be called by users of NewTypeParam after the bound's underlying is
// returns the receiver t is safe for concurrent use. // fully defined, and before using the type parameter in any way other than to
// form other types. Once SetConstraint returns the receiver, t is safe for
// concurrent use.
func (t *TypeParam) SetConstraint(bound Type) { func (t *TypeParam) SetConstraint(bound Type) {
if bound == nil { if bound == nil {
panic("nil constraint") panic("nil constraint")
@ -93,9 +95,12 @@ func (t *TypeParam) String() string { return TypeString(t, nil) }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Implementation // Implementation
func (t *TypeParam) cleanup() {
t.iface()
t.check = nil
}
// iface returns the constraint interface of t. // 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 { func (t *TypeParam) iface() *Interface {
bound := t.bound bound := t.bound
@ -136,16 +141,6 @@ func (t *TypeParam) iface() *Interface {
return ityp 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 // 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 // all calls to f returned true. If there are no specific terms, is
// returns the result of f(nil). // returns the result of f(nil).

Some files were not shown because too many files have changed in this diff Show More