mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
[dev.boringcrypto.go1.18] all: merge go1.18 into dev.boringcrypto.go1.18
Change-Id: Ib2bfa4940b7b054d54f8ee998c63beb32c6afd51
This commit is contained in:
commit
0622ea4d90
97
CONTRIBUTORS
97
CONTRIBUTORS
@ -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>
|
||||||
|
@ -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
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
branch: dev.boringcrypto
|
branch: dev.boringcrypto.go1.18
|
||||||
parent-branch: master
|
parent-branch: master
|
||||||
|
155
doc/go1.18.html
155
doc/go1.18.html
@ -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>
|
||||||
|
1046
doc/go_spec.html
1046
doc/go_spec.html
File diff suppressed because it is too large
Load Diff
@ -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) &&
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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",
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
@ -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 {
|
||||||
|
@ -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},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)))
|
||||||
|
@ -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).
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -6,7 +6,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"./mysort"
|
"cmd/compile/internal/test/testdata/mysort"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MyString struct {
|
type MyString struct {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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))
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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]
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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...)
|
||||||
|
@ -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 {
|
||||||
|
@ -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.
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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() {
|
||||||
|
@ -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)
|
||||||
|
@ -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]
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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]]()
|
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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{}
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
|
@ -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) {
|
||||||
|
@ -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]{}
|
||||||
|
@ -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)
|
||||||
|
@ -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]
|
||||||
}
|
}
|
||||||
|
25
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49482.go2
vendored
Normal file
25
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49482.go2
vendored
Normal 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{}
|
@ -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]) {
|
||||||
|
11
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49735.go2
vendored
Normal file
11
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49735.go2
vendored
Normal 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)
|
||||||
|
}
|
@ -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 */ ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
47
src/cmd/compile/internal/types2/testdata/fixedbugs/issue50755.go2
vendored
Normal file
47
src/cmd/compile/internal/types2/testdata/fixedbugs/issue50755.go2
vendored
Normal 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
|
||||||
|
}
|
@ -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.
|
||||||
|
@ -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) {
|
||||||
|
18
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51145.go
vendored
Normal file
18
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51145.go
vendored
Normal 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
|
18
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51158.go2
vendored
Normal file
18
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51158.go2
vendored
Normal 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)
|
||||||
|
}
|
164
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51229.go2
vendored
Normal file
164
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51229.go2
vendored
Normal 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)
|
||||||
|
}
|
30
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go2
vendored
Normal file
30
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go2
vendored
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
27
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51233.go2
vendored
Normal file
27
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51233.go2
vendored
Normal 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()
|
||||||
|
}
|
46
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51257.go2
vendored
Normal file
46
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51257.go2
vendored
Normal 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},
|
||||||
|
})
|
||||||
|
}
|
16
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51335.go2
vendored
Normal file
16
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51335.go2
vendored
Normal 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 */ }}
|
||||||
|
}
|
18
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2
vendored
Normal file
18
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2
vendored
Normal 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() {}
|
13
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51360.go
vendored
Normal file
13
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51360.go
vendored
Normal 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 */
|
||||||
|
}
|
24
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51376.go2
vendored
Normal file
24
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51376.go2
vendored
Normal 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
|
||||||
|
}
|
17
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51386.go2
vendored
Normal file
17
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51386.go2
vendored
Normal 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("")
|
||||||
|
}
|
17
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51437.go
vendored
Normal file
17
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51437.go
vendored
Normal 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
|
||||||
|
}
|
||||||
|
}
|
54
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51472.go2
vendored
Normal file
54
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51472.go2
vendored
Normal 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]
|
||||||
|
}
|
7
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51509.go
vendored
Normal file
7
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51509.go
vendored
Normal 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
|
17
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51578.go2
vendored
Normal file
17
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51578.go2
vendored
Normal 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) {}
|
13
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51593.go2
vendored
Normal file
13
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51593.go2
vendored
Normal 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
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user