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 Opie <amtopie@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 Sergeyev <abc@alexsergeyev.com>
|
||||
Alex Tokarev <aleksator@gmail.com>
|
||||
@ -135,6 +136,7 @@ Alexander Klauer <Alexander.Klauer@googlemail.com>
|
||||
Alexander Kucherenko <alxkchr@gmail.com>
|
||||
Alexander Larsson <alexander.larsson@gmail.com>
|
||||
Alexander Lourier <aml@rulezz.ru>
|
||||
Alexander Melentyev <alexander@melentyev.org>
|
||||
Alexander Menzhinsky <amenzhinsky@gmail.com>
|
||||
Alexander Morozov <lk4d4math@gmail.com>
|
||||
Alexander Neumann <alexander@bumpern.de>
|
||||
@ -145,6 +147,7 @@ Alexander Polcyn <apolcyn@google.com>
|
||||
Alexander Rakoczy <alex@golang.org>
|
||||
Alexander Reece <awreece@gmail.com>
|
||||
Alexander Surma <surma@surmair.de>
|
||||
Alexander Yastrebov <yastrebov.alex@gmail.com>
|
||||
Alexander Zhavnerchik <alex.vizor@gmail.com>
|
||||
Alexander Zillion <alex@alexzillion.com>
|
||||
Alexander Zolotov <goldifit@gmail.com>
|
||||
@ -179,6 +182,7 @@ Alok Menghrajani <alok.menghrajani@gmail.com>
|
||||
Alwin Doss <alwindoss84@gmail.com>
|
||||
Aman Gupta <aman@tmm1.net>
|
||||
Amarjeet Anand <amarjeetanandsingh@gmail.com>
|
||||
Amelia Downs <adowns@vmware.com>
|
||||
Amir Mohammad Saied <amir@gluegadget.com>
|
||||
Amit Kumar <mittalmailbox@gmail.com>
|
||||
Amr Mohammed <merodiro@gmail.com>
|
||||
@ -191,6 +195,7 @@ Anatol Pomozov <anatol.pomozov@gmail.com>
|
||||
Anders Pearson <anders@columbia.edu>
|
||||
Anderson Queiroz <contato@andersonq.eti.br>
|
||||
André Carvalho <asantostc@gmail.com>
|
||||
Andre Marianiello <andremarianiello@users.noreply.github.com>
|
||||
André Martins <aanm90@gmail.com>
|
||||
Andre Nathan <andrenth@gmail.com>
|
||||
Andrea Nodari <andrea.nodari91@gmail.com>
|
||||
@ -221,6 +226,7 @@ Andrew Gerrand <adg@golang.org>
|
||||
Andrew Harding <andrew@spacemonkey.com>
|
||||
Andrew Jackura <ajackura@google.com>
|
||||
Andrew Kemm <andrewkemm@gmail.com>
|
||||
Andrew LeFevre <capnspacehook@gmail.com>
|
||||
Andrew Louis <alouis@digitalocean.com>
|
||||
Andrew Lutomirski <andy@luto.us>
|
||||
Andrew Medvedev <andrew.y.medvedev@gmail.com>
|
||||
@ -234,6 +240,7 @@ Andrew Stormont <astormont@racktopsystems.com>
|
||||
Andrew Stribblehill <ads@wompom.org>
|
||||
Andrew Szeto <andrew@jabagawee.com>
|
||||
Andrew Todd <andrew.todd@wework.com>
|
||||
Andrew Wansink <wansink@uber.com>
|
||||
Andrew Werner <andrew@upthere.com> <awerner32@gmail.com>
|
||||
Andrew Wilkins <axwalk@gmail.com>
|
||||
Andrew Williams <williams.andrew@gmail.com>
|
||||
@ -283,6 +290,7 @@ Antonio Bibiano <antbbn@gmail.com>
|
||||
Antonio Garcia <garcia.olais@gmail.com>
|
||||
Antonio Huete Jimenez <tuxillo@quantumachine.net>
|
||||
Antonio Murdaca <runcom@redhat.com>
|
||||
Antonio Ojea <antonio.ojea.garcia@gmail.com>
|
||||
Antonio Troina <thoeni@gmail.com>
|
||||
Anze Kolar <me@akolar.com>
|
||||
Aofei Sheng <aofei@aofeisheng.com>
|
||||
@ -290,6 +298,7 @@ Apisak Darakananda <pongad@gmail.com>
|
||||
Aram Hăvărneanu <aram@mgk.ro>
|
||||
Araragi Hokuto <kanseihonbucho@protonmail.com>
|
||||
Arash Bina <arash@arash.io>
|
||||
Archana Ravindar <aravind5@in.ibm.com>
|
||||
Arda Güçlü <ardaguclu@gmail.com>
|
||||
Areski Belaid <areski@gmail.com>
|
||||
Ariel Mashraki <ariel@mashraki.co.il>
|
||||
@ -299,6 +308,7 @@ Arnaud Ysmal <arnaud.ysmal@gmail.com>
|
||||
Arne Hormann <arnehormann@gmail.com>
|
||||
Arnout Engelen <arnout@bzzt.net>
|
||||
Aron Nopanen <aron.nopanen@gmail.com>
|
||||
Arran Walker <arran.walker@fiveturns.org>
|
||||
Artem Alekseev <artem.alekseev@intel.com>
|
||||
Artem Khvastunov <artem.khvastunov@jetbrains.com>
|
||||
Artem Kolin <artemkaxboy@gmail.com>
|
||||
@ -337,6 +347,7 @@ Balaram Makam <bmakam.qdt@qualcommdatacenter.com>
|
||||
Balazs Lecz <leczb@google.com>
|
||||
Baokun Lee <nototon@gmail.com> <bk@golangcn.org>
|
||||
Barnaby Keene <accounts@southcla.ws>
|
||||
Bartłomiej Klimczak <bartlomiej.klimczak88@gmail.com>
|
||||
Bartosz Grzybowski <melkorm@gmail.com>
|
||||
Bartosz Oler <brtsz@google.com>
|
||||
Bassam Ojeil <bojeil@google.com>
|
||||
@ -368,6 +379,7 @@ Benny Siegert <bsiegert@gmail.com>
|
||||
Benoit Sigoure <tsunanet@gmail.com>
|
||||
Berengar Lehr <Berengar.Lehr@gmx.de>
|
||||
Berkant Ipek <41230766+0xbkt@users.noreply.github.com>
|
||||
Beth Brown <ecbrown@google.com>
|
||||
Bharath Kumar Uppala <uppala.bharath@gmail.com>
|
||||
Bharath Thiruveedula <tbharath91@gmail.com>
|
||||
Bhavin Gandhi <bhavin7392@gmail.com>
|
||||
@ -430,6 +442,7 @@ Brian Ketelsen <bketelsen@gmail.com>
|
||||
Brian Slesinsky <skybrian@google.com>
|
||||
Brian Smith <ohohvi@gmail.com>
|
||||
Brian Starke <brian.starke@gmail.com>
|
||||
Bruce Huang <helbingxxx@gmail.com>
|
||||
Bryan Alexander <Kozical@msn.com>
|
||||
Bryan Boreham <bjboreham@gmail.com>
|
||||
Bryan C. Mills <bcmills@google.com>
|
||||
@ -482,17 +495,21 @@ Charles Kenney <charlesc.kenney@gmail.com>
|
||||
Charles L. Dorian <cldorian@gmail.com>
|
||||
Charles Lee <zombie.fml@gmail.com>
|
||||
Charles Weill <weill@google.com>
|
||||
Charlie Getzen <charlie@bolt.com>
|
||||
Charlie Moog <moogcharlie@gmail.com>
|
||||
Charlotte Brandhorst-Satzkorn <catzkorn@gmail.com>
|
||||
Chauncy Cullitan <chauncyc@google.com>
|
||||
Chen Zhidong <njutczd@gmail.com>
|
||||
Chen Zhihan <energiehund@gmail.com>
|
||||
Cheng Wang <wangchengiscool@gmail.com>
|
||||
Cherry Mui <cherryyz@google.com>
|
||||
Chew Choon Keat <choonkeat@gmail.com>
|
||||
Chia-Chi Hsu <wuchi5457@gmail.com>
|
||||
Chiawen Chen <golopot@gmail.com>
|
||||
Chirag Sukhala <cchirag77@gmail.com>
|
||||
Cholerae Hu <choleraehyq@gmail.com>
|
||||
Chotepud Teo <AlexRouSg@users.noreply.github.com>
|
||||
Chressie Himpel <chressie@google.com>
|
||||
Chris Ball <chris@printf.net>
|
||||
Chris Biscardi <chris@christopherbiscardi.com>
|
||||
Chris Broadfoot <cbro@golang.org>
|
||||
@ -570,6 +587,7 @@ Cuong Manh Le <cuong@orijtech.com>
|
||||
Curtis La Graff <curtis@lagraff.me>
|
||||
Cyrill Schumacher <cyrill@schumacher.fm>
|
||||
Dai Jie <gzdaijie@gmail.com>
|
||||
Dai Wentao <dwt136@gmail.com>
|
||||
Daisuke Fujita <dtanshi45@gmail.com>
|
||||
Daisuke Suzuki <daisuzu@gmail.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 Lublin <daniel@lublin.se>
|
||||
Daniel Mangum <georgedanielmangum@gmail.com>
|
||||
Daniel Marshall <daniel.marshall2@ibm.com>
|
||||
Daniel Martí <mvdan@mvdan.cc>
|
||||
Daniel McCarney <cpu@letsencrypt.org>
|
||||
Daniel Morsing <daniel.morsing@gmail.com>
|
||||
@ -727,6 +746,7 @@ Dmitry Mottl <dmitry.mottl@gmail.com>
|
||||
Dmitry Neverov <dmitry.neverov@gmail.com>
|
||||
Dmitry Savintsev <dsavints@gmail.com>
|
||||
Dmitry Yakunin <nonamezeil@gmail.com>
|
||||
Dmytro Shynkevych <dm.shynk@gmail.com>
|
||||
Doga Fincan <doga@icloud.com>
|
||||
Domas Tamašauskas <puerdomus@gmail.com>
|
||||
Domen Ipavec <domen@ipavec.net>
|
||||
@ -751,6 +771,7 @@ Dustin Herbison <djherbis@gmail.com>
|
||||
Dustin Long <dustmop@gmail.com>
|
||||
Dustin Sallings <dsallings@gmail.com>
|
||||
Dustin Shields-Cloues <dcloues@gmail.com>
|
||||
Dustin Spicuzza <dustin.spicuzza@gmail.com>
|
||||
Dvir Volk <dvir@everything.me> <dvirsky@gmail.com>
|
||||
Dylan Waits <dylan@waits.io>
|
||||
Ed Schouten <ed@nuxi.nl>
|
||||
@ -810,9 +831,11 @@ Erin Masatsugu <erin.masatsugu@gmail.com>
|
||||
Ernest Chiang <ernest_chiang@htc.com>
|
||||
Erwin Oegema <blablaechthema@hotmail.com>
|
||||
Esko Luontola <esko.luontola@gmail.com>
|
||||
Ethan Anderson <eanderson@atlassian.com>
|
||||
Ethan Burns <eaburns@google.com>
|
||||
Ethan Hur <ethan0311@gmail.com>
|
||||
Ethan Miller <eamiller@us.ibm.com>
|
||||
Ethan Reesor <ethan.reesor@gmail.com>
|
||||
Euan Kemp <euank@euank.com>
|
||||
Eugene Formanenko <mo4islona@gmail.com>
|
||||
Eugene Kalinin <e.v.kalinin@gmail.com>
|
||||
@ -831,8 +854,10 @@ Evgeniy Polyakov <zbr@ioremap.net>
|
||||
Ewan Chou <coocood@gmail.com>
|
||||
Ewan Valentine <ewan.valentine89@gmail.com>
|
||||
Eyal Posener <posener@gmail.com>
|
||||
F. Talha Altınel <talhaaltinel@hotmail.com>
|
||||
Fabian Wickborn <fabian@wickborn.net>
|
||||
Fabian Zaremba <fabian@youremail.eu>
|
||||
Fabio Falzoi <fabio.falzoi84@gmail.com>
|
||||
Fabrizio Milo <mistobaan@gmail.com>
|
||||
Faiyaz Ahmed <ahmedf@vmware.com>
|
||||
Fan Hongjian <fan.howard@gmail.com>
|
||||
@ -861,21 +886,25 @@ Firmansyah Adiputra <frm.adiputra@gmail.com>
|
||||
Florian Forster <octo@google.com>
|
||||
Florian Uekermann <florian@uekermann-online.de> <f1@uekermann-online.de>
|
||||
Florian Weimer <fw@deneb.enyo.de>
|
||||
Florin Papa <fpapa@google.com>
|
||||
Florin Patan <florinpatan@gmail.com>
|
||||
Folke Behrens <folke@google.com>
|
||||
Ford Hurley <ford.hurley@gmail.com>
|
||||
Forest Johnson <forest.n.johnson@gmail.com>
|
||||
Francesc Campoy <campoy@golang.org>
|
||||
Francesco Guardiani <francescoguard@gmail.com>
|
||||
Francesco Renzi <rentziass@gmail.com>
|
||||
Francisco Claude <fclaude@recoded.cl>
|
||||
Francisco Rojas <francisco.rojas.gallegos@gmail.com>
|
||||
Francisco Souza <franciscossouza@gmail.com>
|
||||
Frank Chiarulli Jr <frank@frankchiarulli.com>
|
||||
Frank Schroeder <frank.schroeder@gmail.com>
|
||||
Frank Somers <fsomers@arista.com>
|
||||
Frederic Guillot <frederic.guillot@gmail.com>
|
||||
Frederick Kelly Mayle III <frederickmayle@gmail.com>
|
||||
Frederik Ring <frederik.ring@gmail.com>
|
||||
Frederik Zipp <fzipp@gmx.de>
|
||||
Frediano Ziglio <freddy77@gmail.com>
|
||||
Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
|
||||
Fredrik Forsmo <fredrik.forsmo@gmail.com>
|
||||
Fredrik Wallgren <fredrik.wallgren@gmail.com>
|
||||
@ -914,6 +943,7 @@ Geon Kim <geon0250@gmail.com>
|
||||
Georg Reinke <guelfey@gmail.com>
|
||||
George Gkirtsou <ggirtsou@gmail.com>
|
||||
George Hartzell <hartzell@alerce.com>
|
||||
George Looshch <looshch@loosh.ch>
|
||||
George Shammas <george@shamm.as> <georgyo@gmail.com>
|
||||
George Tsilias <tsiliasg@gmail.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 @geedchin (11672310) <geedchin@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 @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 @Illirgway (5428603) <illirgway@gmail.com>
|
||||
GitHub User @itchyny (375258) <itchyny@hatena.ne.jp>
|
||||
GitHub User @jinmiaoluo (39730824) <jinmiaoluo@icloud.com>
|
||||
GitHub User @jopbrown (6345470) <msshane2008@gmail.com>
|
||||
GitHub User @kazyshr (30496953) <kazyshr0301@gmail.com>
|
||||
GitHub User @kc1212 (1093806) <kc1212@users.noreply.github.com>
|
||||
GitHub User @komisan19 (18901496) <komiyama6219@gmail.com>
|
||||
GitHub User @korzhao (64203902) <korzhao95@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 @linguohua (3434367) <lghchinaidea@gmail.com>
|
||||
GitHub User @lloydchang (1329685) <lloydchang@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 @madiganz (18340029) <zacharywmadigan@gmail.com>
|
||||
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 @nu50218 (40682920) <nu_ll@icloud.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 @po3rin (29445112) <abctail30@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 @qcrao (7698088) <qcrao91@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 @SataQiu (9354727) <shidaqiu2018@gmail.com>
|
||||
GitHub User @seifchen (23326132) <chenxuefeng1207@gmail.com>
|
||||
GitHub User @shogo-ma (9860598) <Choroma194@gmail.com>
|
||||
GitHub User @sivchari (55221074) <shibuuuu5@gmail.com>
|
||||
GitHub User @skanehira (7888591) <sho19921005@gmail.com>
|
||||
GitHub User @soolaugust (10558124) <soolaugust@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 @tell-k (26263) <ffk2005@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 @utkarsh-extc (53217283) <utkarsh.extc@gmail.com>
|
||||
GitHub User @witchard (4994659) <witchard@hotmail.co.uk>
|
||||
GitHub User @wmdngngng (22067700) <wangmingdong@gmail.com>
|
||||
GitHub User @wolf1996 (5901874) <ksgiv37@gmail.com>
|
||||
GitHub User @yah01 (12216890) <kagaminehuan@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 Rezende <guilhermebr@gmail.com>
|
||||
Guilherme Souza <32180229+gqgs@users.noreply.github.com>
|
||||
Guillaume Blaquiere <guillaume.blaquiere@gmail.com>
|
||||
Guillaume J. Charmes <guillaume@charmes.net>
|
||||
Guillaume Sottas <guillaumesottas@gmail.com>
|
||||
Günther Noack <gnoack@google.com>
|
||||
Guobiao Mei <meiguobiao@gmail.com>
|
||||
Guodong Li <guodongli@google.com>
|
||||
Guoliang Wang <iamwgliang@gmail.com>
|
||||
Guoqi Chen <chenguoqi@loongson.cn>
|
||||
Gustav Paul <gustav.paul@gmail.com>
|
||||
Gustav Westling <gustav@westling.xyz>
|
||||
Gustavo Franco <gustavorfranco@gmail.com>
|
||||
@ -1050,6 +1097,8 @@ Hang Qian <hangqian90@gmail.com>
|
||||
Hanjun Kim <hallazzang@gmail.com>
|
||||
Hanlin He <hanling.he@gmail.com>
|
||||
Hanlin Shi <shihanlin9@gmail.com>
|
||||
Hans Nielsen <hans@stackallocated.com>
|
||||
Hao Mou <mouhao.mu@gmail.com>
|
||||
Haoran Luo <haoran.luo@chaitin.com>
|
||||
Haosdent Huang <haosdent@gmail.com>
|
||||
Harald Nordgren <haraldnordgren@gmail.com>
|
||||
@ -1126,6 +1175,7 @@ Igor Zhilianin <igor.zhilianin@gmail.com>
|
||||
Ikko Ashimine <eltociear@gmail.com>
|
||||
Illya Yalovyy <yalovoy@gmail.com>
|
||||
Ilya Chukov <56119080+Elias506@users.noreply.github.com>
|
||||
Ilya Mateyko <me@astrophena.name>
|
||||
Ilya Sinelnikov <sidhmangh@gmail.com>
|
||||
Ilya Tocar <ilya.tocar@intel.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>
|
||||
Jack Britton <jackxbritton@gmail.com>
|
||||
Jack Lindamood <jlindamo@justin.tv>
|
||||
Jack You <jamesyou@google.com>
|
||||
Jacob Baskin <jbaskin@google.com>
|
||||
Jacob Blain Christen <dweomer5@gmail.com>
|
||||
Jacob H. Haven <jacob@cloudflare.com>
|
||||
@ -1165,6 +1216,7 @@ Jacob Walker <jacobwalker0814@gmail.com>
|
||||
Jaden Teng <long.asyn@gmail.com>
|
||||
Jae Kwon <jae@tendermint.com>
|
||||
Jake B <doogie1012@gmail.com>
|
||||
Jake Ciolek <jakub@ciolek.dev>
|
||||
Jakob Borg <jakob@nym.se>
|
||||
Jakob Weisblat <jakobw@mit.edu>
|
||||
Jakub Čajka <jcajka@redhat.com>
|
||||
@ -1183,6 +1235,7 @@ James Eady <jmeady@google.com>
|
||||
James Fennell <jpfennell@google.com>
|
||||
James Fysh <james.fysh@gmail.com>
|
||||
James Gray <james@james4k.com>
|
||||
James Harris <mailjamesharris@gmail.com>
|
||||
James Hartig <fastest963@gmail.com>
|
||||
James Kasten <jdkasten@google.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-François Bustarret <jf@bustarret.com>
|
||||
Jean-Francois Cantin <jfcantin@gmail.com>
|
||||
Jean-Hadrien Chabran <jh@chabran.fr>
|
||||
Jean-Marc Eurin <jmeurin@google.com>
|
||||
Jean-Nicolas Moal <jn.moal@gmail.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 Sickel <jas@corpus-callosum.com>
|
||||
Jeff Wendling <jeff@spacemonkey.com>
|
||||
Jeff Wentworth <j.wentworth@gmail.com>
|
||||
Jeff Widman <jeff@jeffwidman.com>
|
||||
Jeffrey H <jeffreyh192@gmail.com>
|
||||
Jelte Fennema <github-tech@jeltef.nl>
|
||||
@ -1282,6 +1337,7 @@ Jesús Espino <jespinog@gmail.com>
|
||||
Jia Zhan <jzhan@uber.com>
|
||||
Jiacai Liu <jiacai2050@gmail.com>
|
||||
Jiahao Lu <lujjjh@gmail.com>
|
||||
Jiahua Wang <wjh180909@gmail.com>
|
||||
Jianing Yu <jnyu@google.com>
|
||||
Jianqiao Li <jianqiaoli@google.com>
|
||||
Jiayu Yi <yijiayu@gmail.com>
|
||||
@ -1298,10 +1354,12 @@ Jingcheng Zhang <diogin@gmail.com>
|
||||
Jingguo Yao <yaojingguo@gmail.com>
|
||||
Jingnan Si <jingnan.si@gmail.com>
|
||||
Jinkun Zhang <franksnolf@gmail.com>
|
||||
Jinwen Wo <wojinwen@huawei.com>
|
||||
Jiong Du <londevil@gmail.com>
|
||||
Jirka Daněk <dnk@mail.muni.cz>
|
||||
Jiulong Wang <jiulongw@gmail.com>
|
||||
Joakim Sernbrant <serbaut@gmail.com>
|
||||
Jochen Weber <jochen.weber80@gmail.com>
|
||||
Joe Bowbeer <joe.bowbeer@gmail.com>
|
||||
Joe Cortopassi <joe@joecortopassi.com>
|
||||
Joe Farrell <joe2farrell@gmail.com>
|
||||
@ -1324,6 +1382,7 @@ Johan Euphrosine <proppy@google.com>
|
||||
Johan Jansson <johan.jansson@iki.fi>
|
||||
Johan Knutzen <johan@senri.se>
|
||||
Johan Sageryd <j@1616.se>
|
||||
Johannes Altmanninger <aclopte@gmail.com>
|
||||
Johannes Huning <johannes.huning@gmail.com>
|
||||
John Asmuth <jasmuth@gmail.com>
|
||||
John Bampton <jbampton@gmail.com>
|
||||
@ -1338,10 +1397,12 @@ John Howard Palevich <jack.palevich@gmail.com>
|
||||
John Jago <johnjago@protonmail.com>
|
||||
John Jeffery <jjeffery@sp.com.au>
|
||||
John Jenkins <twodopeshaggy@gmail.com>
|
||||
John Kelly <jkelly@squarespace.com>
|
||||
John Leidegren <john.leidegren@gmail.com>
|
||||
John McCabe <john@johnmccabe.net>
|
||||
John Moore <johnkenneth.moore@gmail.com>
|
||||
John Newlin <jnewlin@google.com>
|
||||
John Olheiser <john.olheiser@gmail.com>
|
||||
John Papandriopoulos <jpap.code@gmail.com>
|
||||
John Potocny <johnp@vividcortex.com>
|
||||
John R. Lenton <jlenton@gmail.com>
|
||||
@ -1382,6 +1443,7 @@ Jordan Rupprecht <rupprecht@google.com>
|
||||
Jordi Martin <jordimartin@gmail.com>
|
||||
Jorge Araya <jorgejavieran@yahoo.com.mx>
|
||||
Jorge L. Fatta <jorge.fatta@auth0.com>
|
||||
Jorge Troncoso <jatron@google.com>
|
||||
Jos Visser <josv@google.com>
|
||||
Josa Gesell <josa@gesell.me>
|
||||
Jose Luis Vázquez González <josvazg@gmail.com>
|
||||
@ -1508,6 +1570,7 @@ Keyuan Li <keyuanli123@gmail.com>
|
||||
Kezhu Wang <kezhuw@gmail.com>
|
||||
Khosrow Moossavi <khos2ow@gmail.com>
|
||||
Kieran Colford <kieran@kcolford.com>
|
||||
Kieran Gorman <kieran.j.gorman@gmail.com>
|
||||
Kim Shrier <kshrier@racktopsystems.com>
|
||||
Kim Yongbin <kybinz@gmail.com>
|
||||
Kir Kolyshkin <kolyshkin@gmail.com>
|
||||
@ -1577,6 +1640,7 @@ Leonel Quinteros <leonel.quinteros@gmail.com>
|
||||
Lev Shamardin <shamardin@gmail.com>
|
||||
Lewin Bormann <lewin.bormann@gmail.com>
|
||||
Lewis Waddicor <nemesismk2@gmail.com>
|
||||
Li-Yu Yu <aaronyu@google.com>
|
||||
Liam Haworth <liam@haworth.id.au>
|
||||
Lily Chung <lilithkchung@gmail.com>
|
||||
Lingchao Xin <douglarek@gmail.com>
|
||||
@ -1657,7 +1721,9 @@ Mark Adams <mark@markadams.me>
|
||||
Mark Bucciarelli <mkbucc@gmail.com>
|
||||
Mark Dain <mark@markdain.net>
|
||||
Mark Glines <mark@glines.org>
|
||||
Mark Hansen <markhansen@google.com>
|
||||
Mark Harrison <marhar@google.com>
|
||||
Mark Jeffery <dandare100@gmail.com>
|
||||
Mark Percival <m@mdp.im>
|
||||
Mark Pulford <mark@kyne.com.au>
|
||||
Mark Rushakoff <mark.rushakoff@gmail.com>
|
||||
@ -1686,7 +1752,7 @@ Martin Hoefling <martin.hoefling@gmx.de>
|
||||
Martin Kreichgauer <martinkr@google.com>
|
||||
Martin Kunc <martinkunc@users.noreply.github.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 Olsen <github.com@martinolsen.net>
|
||||
Martin Olsson <martin@minimum.se>
|
||||
@ -1741,6 +1807,7 @@ Matthew Denton <mdenton@skyportsystems.com>
|
||||
Matthew Holt <Matthew.Holt+git@gmail.com>
|
||||
Matthew Horsnell <matthew.horsnell@gmail.com>
|
||||
Matthew Waters <mwwaters@gmail.com>
|
||||
Matthias Dötsch <matze@mdoetsch.de>
|
||||
Matthias Frei <matthias.frei@inf.ethz.ch>
|
||||
Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
|
||||
Matthieu Olivier <olivier.matthieu@gmail.com>
|
||||
@ -1814,6 +1881,7 @@ Michal Bohuslávek <mbohuslavek@gmail.com>
|
||||
Michal Cierniak <cierniak@google.com>
|
||||
Michał Derkacz <ziutek@lnet.pl>
|
||||
Michal Franc <lam.michal.franc@gmail.com>
|
||||
Michal Hruby <michal@axiom.co>
|
||||
Michał Łowicki <mlowicki@gmail.com>
|
||||
Michal Pristas <michal.pristas@gmail.com>
|
||||
Michal Rostecki <mrostecki@suse.de>
|
||||
@ -1844,6 +1912,7 @@ Mike Solomon <msolo@gmail.com>
|
||||
Mike Strosaker <strosake@us.ibm.com>
|
||||
Mike Tsao <mike@sowbug.com>
|
||||
Mike Wiacek <mjwiacek@google.com>
|
||||
Mikhail Faraponov <11322032+moredure@users.noreply.github.com>
|
||||
Mikhail Fesenko <proggga@gmail.com>
|
||||
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
Mikhail Panchenko <m@mihasya.com>
|
||||
@ -1870,6 +1939,7 @@ Moritz Fain <moritz@fain.io>
|
||||
Moriyoshi Koizumi <mozo@mozo.jp>
|
||||
Morten Siebuhr <sbhr@sbhr.dk>
|
||||
Môshe van der Sterre <moshevds@gmail.com>
|
||||
Mostafa Solati <mostafa.solati@gmail.com>
|
||||
Mostyn Bramley-Moore <mostyn@antipode.se>
|
||||
Mrunal Patel <mrunalp@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 Petroni <npetroni@cs.umd.edu>
|
||||
Nick Robinson <nrobinson13@gmail.com>
|
||||
Nick Sherron <nsherron90@gmail.com>
|
||||
Nick Smolin <nick27surgut@gmail.com>
|
||||
Nicolas BRULEZ <n.brulez@gmail.com>
|
||||
Nicolas Kaiser <nikai@nikai.net>
|
||||
@ -1956,6 +2027,7 @@ Noah Santschi-Cooney <noah@santschi-cooney.ch>
|
||||
Noble Johnson <noblepoly@gmail.com>
|
||||
Nodir Turakulov <nodir@google.com>
|
||||
Noel Georgi <git@frezbo.com>
|
||||
Nooras Saba <saba@golang.org>
|
||||
Norberto Lopes <nlopes.ml@gmail.com>
|
||||
Norman B. Lancaster <qbradq@gmail.com>
|
||||
Nuno Cruces <ncruces@users.noreply.github.com>
|
||||
@ -1973,6 +2045,7 @@ Oliver Tan <otan@cockroachlabs.com>
|
||||
Oliver Tonnhofer <olt@bogosoft.com>
|
||||
Olivier Antoine <olivier.antoine@gmail.com>
|
||||
Olivier Duperray <duperray.olivier@gmail.com>
|
||||
Olivier Mengué <olivier.mengue@gmail.com>
|
||||
Olivier Poitrey <rs@dailymotion.com>
|
||||
Olivier Saingre <osaingre@gmail.com>
|
||||
Olivier Wulveryck <olivier.wulveryck@gmail.com>
|
||||
@ -1982,6 +2055,7 @@ Ori Bernstein <ori@eigenstate.org>
|
||||
Ori Rawlings <orirawlings@gmail.com>
|
||||
Oryan Moshe <iamoryanmoshe@gmail.com>
|
||||
Osamu TONOMORI <osamingo@gmail.com>
|
||||
Oscar Söderlund <oscar.soderlund@einride.tech>
|
||||
Özgür Kesim <oec-go@kesim.org>
|
||||
Pablo Caderno <kaderno@gmail.com>
|
||||
Pablo Lalloni <plalloni@gmail.com>
|
||||
@ -2014,6 +2088,7 @@ Patrick Pelletier <pp.pelletier@gmail.com>
|
||||
Patrick Riley <pfr@google.com>
|
||||
Patrick Smith <pat42smith@gmail.com>
|
||||
Patrik Lundin <patrik@sigterm.se>
|
||||
Patrik Nyblom <pnyb@google.com>
|
||||
Paul A Querna <paul.querna@gmail.com>
|
||||
Paul Borman <borman@google.com>
|
||||
Paul Boyd <boyd.paul2@gmail.com>
|
||||
@ -2042,6 +2117,7 @@ Paul Wankadia <junyer@google.com>
|
||||
Paulo Casaretto <pcasaretto@gmail.com>
|
||||
Paulo Flabiano Smorigo <pfsmorigo@linux.vnet.ibm.com>
|
||||
Paulo Gomes <paulo.gomes.uk@gmail.com>
|
||||
Pavel Kositsyn <kositsyn.pa@phystech.edu>
|
||||
Pavel Paulau <pavel.paulau@gmail.com>
|
||||
Pavel Watson <watsonpavel@gmail.com>
|
||||
Pavel Zinovkin <pavel.zinovkin@gmail.com>
|
||||
@ -2049,6 +2125,7 @@ Pavlo Sumkin <ymkins@gmail.com>
|
||||
Pawel Knap <pawelknap88@gmail.com>
|
||||
Pawel Szczur <filemon@google.com>
|
||||
Paweł Szulik <pawel.szulik@intel.com>
|
||||
Pedro Lopez Mareque <pedro.lopez.mareque@gmail.com>
|
||||
Pei Xian Chee <luciolas1991@gmail.com>
|
||||
Pei-Ming Wu <p408865@gmail.com>
|
||||
Pen Tree <appletree2479@outlook.com>
|
||||
@ -2164,6 +2241,7 @@ Rhys Hiltner <rhys@justin.tv>
|
||||
Ricardo Padilha <ricardospadilha@gmail.com>
|
||||
Ricardo Pchevuzinske Katz <ricardo.katz@serpro.gov.br>
|
||||
Ricardo Seriani <ricardo.seriani@gmail.com>
|
||||
Rich Hong <hong.rich@gmail.com>
|
||||
Richard Barnes <rlb@ipv.sx>
|
||||
Richard Crowley <r@rcrowley.org>
|
||||
Richard Dingwall <rdingwall@gmail.com>
|
||||
@ -2179,6 +2257,7 @@ Rick Hudson <rlh@golang.org>
|
||||
Rick Sayre <whorfin@gmail.com>
|
||||
Rijnard van Tonder <rvantonder@gmail.com>
|
||||
Riku Voipio <riku.voipio@linaro.org>
|
||||
Riley Avron <ra.git@posteo.net>
|
||||
Risto Jaakko Saarelma <rsaarelm@gmail.com>
|
||||
Rob Earhart <earhart@google.com>
|
||||
Rob Findley <rfindley@google.com>
|
||||
@ -2186,8 +2265,10 @@ Rob Norman <rob.norman@infinitycloud.com>
|
||||
Rob Phoenix <rob@robphoenix.com>
|
||||
Rob Pike <r@golang.org>
|
||||
Robert Ayrapetyan <robert.ayrapetyan@gmail.com>
|
||||
Robert Burke <rebo@google.com>
|
||||
Robert Daniel Kortschak <dan.kortschak@adelaide.edu.au> <dan@kortschak.io>
|
||||
Robert Dinu <r@varp.se>
|
||||
Robert Engels <rengels@ix.netcom.com>
|
||||
Robert Figueiredo <robfig@gmail.com>
|
||||
Robert Griesemer <gri@golang.org>
|
||||
Robert Hencke <robert.hencke@gmail.com>
|
||||
@ -2212,6 +2293,7 @@ Roger Peppe <rogpeppe@gmail.com>
|
||||
Rohan Challa <rohan@golang.org>
|
||||
Rohan Verma <rohanverma2004@gmail.com>
|
||||
Rohith Ravi <entombedvirus@gmail.com>
|
||||
Roi Martin <jroi.martin@gmail.com>
|
||||
Roland Illig <roland.illig@gmx.de>
|
||||
Roland Shoemaker <rolandshoemaker@gmail.com>
|
||||
Romain Baugue <romain.baugue@elwinar.com>
|
||||
@ -2242,6 +2324,7 @@ Ryan Canty <jrcanty@gmail.com>
|
||||
Ryan Dahl <ry@tinyclouds.org>
|
||||
Ryan Hitchman <hitchmanr@gmail.com>
|
||||
Ryan Kohler <ryankohler@google.com>
|
||||
Ryan Leung <rleungx@gmail.com>
|
||||
Ryan Lower <rpjlower@gmail.com>
|
||||
Ryan Roden-Corrent <ryan@rcorre.net>
|
||||
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 Tan <samueltan@google.com>
|
||||
Samuele Pedroni <pedronis@lucediurna.net>
|
||||
San Ye <xyesan@gmail.com>
|
||||
Sander van Harmelen <sander@vanharmelen.nl>
|
||||
Sanjay Menakuru <balasanjay@gmail.com>
|
||||
Santhosh Kumar Tekuri <santhosh.tekuri@gmail.com>
|
||||
@ -2339,6 +2423,7 @@ Shaba Abhiram <shabarivas.abhiram@gmail.com>
|
||||
Shahar Kohanim <skohanim@gmail.com>
|
||||
Shailesh Suryawanshi <ss.shailesh28@gmail.com>
|
||||
Shamil Garatuev <garatuev@gmail.com>
|
||||
Shamim Akhtar <shamim.rhce@gmail.com>
|
||||
Shane Hansen <shanemhansen@gmail.com>
|
||||
Shang Jian Ding <sding3@ncsu.edu>
|
||||
Shaozhen Ding <dsz0111@gmail.com>
|
||||
@ -2375,6 +2460,7 @@ Simon Drake <simondrake1990@gmail.com>
|
||||
Simon Ferquel <simon.ferquel@docker.com>
|
||||
Simon Frei <freisim93@gmail.com>
|
||||
Simon Jefford <simon.jefford@gmail.com>
|
||||
Simon Law <sfllaw@sfllaw.ca>
|
||||
Simon Rawet <simon@rawet.se>
|
||||
Simon Rozman <simon@rozman.si>
|
||||
Simon Ser <contact@emersion.fr>
|
||||
@ -2440,6 +2526,7 @@ Suharsh Sivakumar <suharshs@google.com>
|
||||
Sukrit Handa <sukrit.handa@utoronto.ca>
|
||||
Sunny <me@darkowlzz.space>
|
||||
Suriyaa Sundararuban <suriyaasundararuban@gmail.com>
|
||||
Suvaditya Sur <suvaditya.sur@gmail.com>
|
||||
Suyash <dextrous93@gmail.com>
|
||||
Suzy Mueller <suzmue@golang.org>
|
||||
Sven Almgren <sven@tras.se>
|
||||
@ -2502,6 +2589,7 @@ Thomas Symborski <thomas.symborski@gmail.com>
|
||||
Thomas Wanielista <tomwans@gmail.com>
|
||||
Thorben Krueger <thorben.krueger@gmail.com>
|
||||
Thordur Bjornsson <thorduri@secnorth.net>
|
||||
Tiago Peczenyj <tpeczenyj@weborama.com>
|
||||
Tiago Queiroz <contato@tiago.eti.br>
|
||||
Tianji Wu <the729@gmail.com>
|
||||
Tianon Gravi <admwiggin@gmail.com>
|
||||
@ -2636,6 +2724,7 @@ Vladimir Varankin <nek.narqo@gmail.com>
|
||||
Vojtech Bocek <vbocek@gmail.com>
|
||||
Volker Dobler <dr.volker.dobler@gmail.com>
|
||||
Volodymyr Paprotski <vpaprots@ca.ibm.com>
|
||||
Vyacheslav Pachkov <slava.pach@gmail.com>
|
||||
W. Trevor King <wking@tremily.us>
|
||||
Wade Simmons <wade@wades.im>
|
||||
Wagner Riffel <wgrriffel@gmail.com>
|
||||
@ -2653,6 +2742,7 @@ Wei Guangjing <vcc.163@gmail.com>
|
||||
Wei Xiao <wei.xiao@arm.com>
|
||||
Wei Xikai <xykwei@gmail.com>
|
||||
Weichao Tang <tevic.tt@gmail.com>
|
||||
Weilu Jia <optix2000@gmail.com>
|
||||
Weixie Cui <cuiweixie@gmail.com> <523516579@qq.com>
|
||||
Wembley G. Leach, Jr <wembley.gl@gmail.com>
|
||||
Wenlei (Frank) He <wlhe@google.com>
|
||||
@ -2722,9 +2812,11 @@ Yuichi Nishiwaki <yuichi.nishiwaki@gmail.com>
|
||||
Yuji Yaginuma <yuuji.yaginuma@gmail.com>
|
||||
Yuki Ito <mrno110y@gmail.com>
|
||||
Yuki OKUSHI <huyuumi.dev@gmail.com>
|
||||
Yuki Osaki <yuki.osaki7@gmail.com>
|
||||
Yuki Yugui Sonoda <yugui@google.com>
|
||||
Yukihiro Nishinaka <6elpinal@gmail.com>
|
||||
YunQiang Su <syq@debian.org>
|
||||
Yuntao Wang <ytcoode@gmail.com>
|
||||
Yury Smolsky <yury@smolsky.by>
|
||||
Yusuke Kagiwada <block.rxckin.beats@gmail.com>
|
||||
Yuusei Kuwana <kuwana@kumama.org>
|
||||
@ -2736,7 +2828,9 @@ Zach Gershman <zachgersh@gmail.com>
|
||||
Zach Hoffman <zrhoffman@apache.org>
|
||||
Zach Jones <zachj1@gmail.com>
|
||||
Zachary Amsden <zach@thundertoken.com>
|
||||
Zachary Burkett <zburkett@splitcubestudios.com>
|
||||
Zachary Gershman <zgershman@pivotal.io>
|
||||
Zaiyang Li <zaiyangli777@gmail.com>
|
||||
Zak <zrjknill@gmail.com>
|
||||
Zakatell Kanda <hi@zkanda.io>
|
||||
Zellyn Hunter <zellyn@squareup.com> <zellyn@gmail.com>
|
||||
@ -2745,6 +2839,7 @@ Zhang Boyang <zhangboyang.id@gmail.com>
|
||||
Zheng Dayu <davidzheng23@gmail.com>
|
||||
Zheng Xu <zheng.xu@arm.com>
|
||||
Zhengyu He <hzy@google.com>
|
||||
Zhi Zheng <zhi.zheng052@gmail.com>
|
||||
Zhongpeng Lin <zplin@uber.com>
|
||||
Zhongtao Chen <chenzhongtao@126.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) SetIterValue(*MapIter)
|
||||
pkg reflect, method (Value) UnsafePointer() unsafe.Pointer
|
||||
pkg runtime/debug, method (*BuildInfo) MarshalText() ([]uint8, error)
|
||||
pkg runtime/debug, method (*BuildInfo) UnmarshalText([]uint8) error
|
||||
pkg runtime/debug, func ParseBuildInfo(string) (*BuildInfo, error)
|
||||
pkg runtime/debug, method (*BuildInfo) String() string
|
||||
pkg runtime/debug, type BuildInfo struct, GoVersion string
|
||||
pkg runtime/debug, type BuildInfo struct, Settings []BuildSetting
|
||||
pkg runtime/debug, type BuildSetting struct
|
||||
|
@ -1,2 +1,2 @@
|
||||
branch: dev.boringcrypto
|
||||
branch: dev.boringcrypto.go1.18
|
||||
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>
|
||||
The new
|
||||
<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)
|
||||
a type constraint.
|
||||
</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>.
|
||||
We hope to remove this restriction in Go 1.19.
|
||||
</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 -->
|
||||
Embedding a type parameter, or a pointer to a type parameter, as
|
||||
an unnamed field in a struct type is not permitted. Similarly
|
||||
an unnamed field in a struct type is not permitted. Similarly,
|
||||
embedding a type parameter in an interface type is not permitted.
|
||||
Whether these will ever be permitted is unclear at present.
|
||||
</li>
|
||||
@ -182,7 +192,7 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
|
||||
<p><!-- CL 349595 -->
|
||||
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,
|
||||
and takes advantage of, additional processor features. A detailed
|
||||
description can be found
|
||||
@ -199,6 +209,12 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
now supports the <code>c-archive</code> and <code>c-shared</code> build modes.
|
||||
</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>
|
||||
|
||||
<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>
|
||||
|
||||
<h4 id="go-get"><code>go</code> <code>get</code></h4>
|
||||
|
||||
<p><!-- golang.org/issue/43684 -->
|
||||
<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
|
||||
@ -269,9 +287,25 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
and installs packages, as before.
|
||||
</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 -->
|
||||
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
|
||||
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
|
||||
@ -281,7 +315,7 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
</p>
|
||||
|
||||
<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,
|
||||
assembler, and linker flags (like <code>-gcflags</code>), whether cgo was
|
||||
enabled, and if it was, the values of the cgo environment variables
|
||||
@ -303,6 +337,8 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
<code>debug/buildinfo</code> package from <code>go</code> 1.18+.
|
||||
</p>
|
||||
|
||||
<h4 id="go-mod-download"><code>go</code> <code>mod</code> <code>download</code></h4>
|
||||
|
||||
<p><!-- https://golang.org/issue/44435 -->
|
||||
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>
|
||||
@ -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>.
|
||||
</p>
|
||||
|
||||
<h4 id="go-mod-vendor"><code>go</code> <code>mod</code> <code>vendor</code></h4>
|
||||
|
||||
<p><!-- https://golang.org/issue/47327 -->
|
||||
The <code>go</code> <code>mod</code> <code>vendor</code> subcommand now
|
||||
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.)
|
||||
</p>
|
||||
|
||||
<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-mod-tidy"><code>go</code> <code>mod</code> <code>tidy</code></h4>
|
||||
|
||||
<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
|
||||
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
|
||||
@ -342,11 +375,13 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
module's <code>go.mod</code> file.
|
||||
</p>
|
||||
|
||||
<h4 id="go-work"><code>go</code> <code>work</code></h4>
|
||||
|
||||
<p><!-- https://golang.org/issue/45713 -->
|
||||
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
|
||||
parent directory, or one is specified using the <code>-workfile</code>
|
||||
flag, it will put the <code>go</code> command into workspace mode.
|
||||
parent directory, or one is specified using the <code>GOWORK</code>
|
||||
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
|
||||
determine the set of main modules used as the roots for module
|
||||
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.
|
||||
</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 -->
|
||||
The <code>go</code> command now supports additional command line
|
||||
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>
|
||||
</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 -->
|
||||
<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.
|
||||
</p>
|
||||
|
||||
<h3 id="vet"><code>vet</code></h3>
|
||||
<h3 id="vet">Vet</h3>
|
||||
|
||||
<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><!-- 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.
|
||||
</p>
|
||||
|
||||
@ -502,10 +569,23 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
</p>
|
||||
|
||||
<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.
|
||||
</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>
|
||||
|
||||
<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><!-- CL 345570 -->
|
||||
The methods <a href="/pkg/bufio#Reader.Reset"><code>Reader.Reset</code></a> and
|
||||
<a href="/pkg/bufio#Writer.Reset"><code>Writer.Reset</code></a>
|
||||
The <a href="/pkg/bufio#Reader.Reset"><code>Reader.Reset</code></a> and
|
||||
<a href="/pkg/bufio#Writer.Reset"><code>Writer.Reset</code></a> methods
|
||||
now use the default buffer size when called on objects with a
|
||||
<code>nil</code> buffer.
|
||||
</p>
|
||||
@ -909,6 +989,19 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
field.
|
||||
</li>
|
||||
</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>
|
||||
</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>
|
||||
<dd>
|
||||
<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.
|
||||
</p>
|
||||
</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>
|
||||
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
|
||||
<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.
|
||||
</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
|
||||
future Go release.
|
||||
</p>
|
||||
</dd>
|
||||
</dd><!-- CL 321889 and CL 345486 are optimizations, no need to mention. -->
|
||||
</dl><!-- reflect -->
|
||||
|
||||
<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>
|
||||
</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>
|
||||
<dd>
|
||||
<p><!-- CL 343877 -->
|
||||
@ -1147,7 +1250,7 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
</p>
|
||||
|
||||
<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.
|
||||
</p>
|
||||
</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>
|
||||
<dd>
|
||||
<p><!-- CL 356430 -->
|
||||
<code>Wrapper</code> interface has been removed.
|
||||
The <code>Wrapper</code> interface has been removed.
|
||||
</p>
|
||||
</dd>
|
||||
</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>
|
||||
<dd>
|
||||
<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>.
|
||||
</p>
|
||||
</dd>
|
||||
|
1020
doc/go_spec.html
1020
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
|
||||
// symbolizer program and can't find it.
|
||||
const noSymbolizer = "external symbolizer"
|
||||
// Check if -asan option can correctly print where the error occured.
|
||||
// Check if -asan option can correctly print where the error occurred.
|
||||
if tc.errorLocation != "" &&
|
||||
!strings.Contains(out, tc.errorLocation) &&
|
||||
!strings.Contains(out, noSymbolizer) &&
|
||||
|
@ -6,6 +6,7 @@ package reboot_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@ -26,10 +27,14 @@ func overlayDir(dstRoot, srcRoot string) error {
|
||||
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 {
|
||||
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)
|
||||
for len(suffix) > 0 && suffix[0] == filepath.Separator {
|
||||
@ -37,6 +42,7 @@ func overlayDir(dstRoot, srcRoot string) error {
|
||||
}
|
||||
dstPath := filepath.Join(dstRoot, suffix)
|
||||
|
||||
info, err := entry.Info()
|
||||
perm := info.Mode() & os.ModePerm
|
||||
if info.Mode()&os.ModeSymlink != 0 {
|
||||
info, err = os.Stat(srcPath)
|
||||
@ -46,14 +52,15 @@ func overlayDir(dstRoot, srcRoot string) error {
|
||||
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 info.IsDir() {
|
||||
return os.MkdirAll(dstPath, perm|0200)
|
||||
}
|
||||
|
||||
// If the OS supports symlinks, use them instead of copying bytes.
|
||||
if err := os.Symlink(srcPath, dstPath); err == nil {
|
||||
// If we can use a hard link, do that instead of copying bytes.
|
||||
// Go builds don't like symlinks in some cases, such as go:embed.
|
||||
if err := os.Link(srcPath, dstPath); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestRepeatBootstrap(t *testing.T) {
|
||||
@ -19,16 +20,14 @@ func TestRepeatBootstrap(t *testing.T) {
|
||||
t.Skipf("skipping test that rebuilds the entire toolchain")
|
||||
}
|
||||
|
||||
goroot, err := os.MkdirTemp("", "reboot-goroot")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(goroot)
|
||||
goroot := t.TempDir()
|
||||
|
||||
gorootSrc := filepath.Join(goroot, "src")
|
||||
overlayStart := time.Now()
|
||||
if err := overlayDir(gorootSrc, filepath.Join(runtime.GOROOT(), "src")); err != nil {
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
|
@ -95,11 +95,11 @@ type rune = int32
|
||||
type any = interface{}
|
||||
|
||||
// comparable is an interface that is implemented by all comparable types
|
||||
// (booleans, numbers, strings, pointers, channels, interfaces,
|
||||
// arrays of comparable types, structs whose fields are all comparable types).
|
||||
// (booleans, numbers, strings, pointers, channels, arrays of comparable types,
|
||||
// structs whose fields are all comparable types).
|
||||
// The comparable interface may only be used as a type parameter constraint,
|
||||
// not as the type of a variable.
|
||||
type comparable comparable
|
||||
type comparable interface{ comparable }
|
||||
|
||||
// iota is a predeclared identifier representing the untyped integer ordinal
|
||||
// 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: the result is nil (zero 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) }
|
||||
|
||||
// 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.
|
||||
// If sep is empty, Split splits after each UTF-8 sequence.
|
||||
// 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) }
|
||||
|
||||
// SplitAfter slices s into all subslices after each instance of sep and
|
||||
|
@ -155,7 +155,7 @@ as follows:
|
||||
1. Remember I and FP.
|
||||
1. If T has zero size, add T to the stack sequence S and return.
|
||||
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.
|
||||
|
||||
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.
|
||||
var NoInstrumentPkgs = []string{
|
||||
"runtime/internal/atomic",
|
||||
"runtime/internal/sys",
|
||||
"runtime/internal/math",
|
||||
"runtime/internal/sys",
|
||||
"runtime/internal/syscall",
|
||||
"runtime",
|
||||
"runtime/race",
|
||||
"runtime/msan",
|
||||
|
@ -238,6 +238,15 @@ func (e *escape) goDeferStmt(n *ir.GoDeferStmt) {
|
||||
fn.SetWrapper(true)
|
||||
fn.Nname.SetType(types.NewSignature(types.LocalPkg, nil, nil, nil, nil))
|
||||
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
|
||||
if n.Op() == ir.OGO {
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/logopt"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
)
|
||||
|
||||
@ -243,6 +244,9 @@ func (b *batch) flowClosure(k hole, clo *ir.ClosureExpr) {
|
||||
n.SetByval(!loc.addrtaken && !loc.reassigned && n.Type().Size() <= 128)
|
||||
if !n.Byval() {
|
||||
n.SetAddrtaken(true)
|
||||
if n.Sym().Name == typecheck.LocalDictName {
|
||||
base.FatalfAt(n.Pos(), "dictionary variable not captured by value")
|
||||
}
|
||||
}
|
||||
|
||||
if base.Flag.LowerM > 1 {
|
||||
|
@ -217,6 +217,10 @@ func dumpGlobalConst(n ir.Node) {
|
||||
if ir.ConstOverflow(v, t) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// If the type of the constant is an instantiated generic, we need to emit
|
||||
// that type so the linker knows about it. See issue 51245.
|
||||
_ = reflectdata.TypeLinksym(t)
|
||||
}
|
||||
base.Ctxt.DwarfIntConst(base.Ctxt.Pkgpath, n.Sym().Name, types.TypeSymName(t), ir.IntVal(t, v))
|
||||
}
|
||||
@ -263,6 +267,10 @@ func addGCLocals() {
|
||||
objw.Global(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
|
||||
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)
|
||||
}
|
||||
|
||||
// SetConstraint can't be called if the constraint type is not yet complete.
|
||||
// When type params are created in the 'P' case of (*importReader).obj(),
|
||||
// the associated constraint type may not be complete due to recursion.
|
||||
// Therefore, we defer calling SetConstraint there, and call it here instead
|
||||
// after all types are complete.
|
||||
for _, d := range p.later {
|
||||
d.t.SetConstraint(d.constraint)
|
||||
}
|
||||
// record all referenced packages as imports
|
||||
list := append(([]*types2.Package)(nil), pkgList[1:]...)
|
||||
sort.Sort(byPath(list))
|
||||
@ -191,6 +199,11 @@ func ImportData(imports map[string]*types2.Package, data, path string) (pkg *typ
|
||||
return localpkg, nil
|
||||
}
|
||||
|
||||
type setConstraintArgs struct {
|
||||
t *types2.TypeParam
|
||||
constraint types2.Type
|
||||
}
|
||||
|
||||
type iimporter struct {
|
||||
exportVersion int64
|
||||
ipath string
|
||||
@ -206,6 +219,9 @@ type iimporter struct {
|
||||
tparamIndex map[ident]*types2.TypeParam
|
||||
|
||||
interfaceList []*types2.Interface
|
||||
|
||||
// Arguments for calls to SetConstraint that are deferred due to recursive types
|
||||
later []setConstraintArgs
|
||||
}
|
||||
|
||||
func (p *iimporter) doDecl(pkg *types2.Package, name string) {
|
||||
@ -401,7 +417,11 @@ func (r *importReader) obj(name string) {
|
||||
}
|
||||
iface.MarkImplicit()
|
||||
}
|
||||
t.SetConstraint(constraint)
|
||||
// The constraint type may not be complete, if we
|
||||
// are in the middle of a type recursion involving type
|
||||
// constraints. So, we defer SetConstraint until we have
|
||||
// completely set up all types in ImportData.
|
||||
r.p.later = append(r.p.later, setConstraintArgs{t: t, constraint: constraint})
|
||||
|
||||
case 'V':
|
||||
typ := r.typ()
|
||||
|
@ -133,6 +133,10 @@ type Func struct {
|
||||
// function for go:nowritebarrierrec analysis. Only filled in
|
||||
// if nowritebarrierrecCheck != nil.
|
||||
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 {
|
||||
|
@ -20,7 +20,7 @@ func TestSizeof(t *testing.T) {
|
||||
_32bit uintptr // size on 32bit platforms
|
||||
_64bit uintptr // size on 64bit platforms
|
||||
}{
|
||||
{Func{}, 192, 328},
|
||||
{Func{}, 196, 336},
|
||||
{Name{}, 112, 200},
|
||||
}
|
||||
|
||||
|
@ -362,7 +362,7 @@ func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt {
|
||||
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 {
|
||||
miniStmt
|
||||
Tag Node
|
||||
|
@ -114,7 +114,7 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
|
||||
|
||||
case *syntax.CallExpr:
|
||||
fun := g.expr(expr.Fun)
|
||||
return Call(pos, g.typ(typ), fun, g.exprs(expr.ArgList), expr.HasDots)
|
||||
return g.callExpr(pos, g.typ(typ), fun, g.exprs(expr.ArgList), expr.HasDots)
|
||||
|
||||
case *syntax.IndexExpr:
|
||||
args := unpackListExpr(expr.Index)
|
||||
@ -206,6 +206,53 @@ func (g *irgen) substType(typ *types.Type, tparams *types.Type, targs []ir.Node)
|
||||
return newt
|
||||
}
|
||||
|
||||
// callExpr creates a call expression (which might be a type conversion, built-in
|
||||
// call, or a regular call) and does standard transforms, unless we are in a generic
|
||||
// function.
|
||||
func (g *irgen) callExpr(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) ir.Node {
|
||||
n := ir.NewCallExpr(pos, ir.OCALL, fun, args)
|
||||
n.IsDDD = dots
|
||||
typed(typ, n)
|
||||
|
||||
if fun.Op() == ir.OTYPE {
|
||||
// Actually a type conversion, not a function call.
|
||||
if !g.delayTransform() {
|
||||
return transformConvCall(n)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
if fun, ok := fun.(*ir.Name); ok && fun.BuiltinOp != 0 {
|
||||
if !g.delayTransform() {
|
||||
return transformBuiltin(n)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Add information, now that we know that fun is actually being called.
|
||||
switch fun := fun.(type) {
|
||||
case *ir.SelectorExpr:
|
||||
if fun.Op() == ir.OMETHVALUE {
|
||||
op := ir.ODOTMETH
|
||||
if fun.X.Type().IsInterface() {
|
||||
op = ir.ODOTINTER
|
||||
}
|
||||
fun.SetOp(op)
|
||||
// Set the type to include the receiver, since that's what
|
||||
// later parts of the compiler expect
|
||||
fun.SetType(fun.Selection.Type)
|
||||
}
|
||||
}
|
||||
|
||||
// A function instantiation (even if fully concrete) shouldn't be
|
||||
// transformed yet, because we need to add the dictionary during the
|
||||
// transformation.
|
||||
if fun.Op() != ir.OFUNCINST && !g.delayTransform() {
|
||||
transformCall(n)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// selectorExpr resolves the choice of ODOT, ODOTPTR, OMETHVALUE (eventually
|
||||
// ODOTMETH & ODOTINTER), and OMETHEXPR and deals with embedded fields here rather
|
||||
// than in typecheck.go.
|
||||
@ -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 {
|
||||
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.SetOp(ir.OPTRLIT)
|
||||
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))
|
||||
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 {
|
||||
n := ir.NewBinaryExpr(pos, op, x, y)
|
||||
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)
|
||||
|
||||
// This is the dictionary we want to use.
|
||||
// It may be a constant, or it may be a dictionary acquired from the outer function's dictionary.
|
||||
// It may be a constant, it may be the outer functions's dictionary, or it may be
|
||||
// a subdictionary acquired from the outer function's dictionary.
|
||||
// For the latter, dictVar is a variable in the outer function's scope, set to the subdictionary
|
||||
// read from the outer function's dictionary.
|
||||
var dictVar *ir.Name
|
||||
@ -640,6 +641,11 @@ func (g *genInst) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMe
|
||||
// over any pointer)
|
||||
recvType := nameNode.Type().Recv().Type
|
||||
recvType = deref(recvType)
|
||||
if recvType.IsFullyInstantiated() {
|
||||
// Get the type of the base generic type, so we get
|
||||
// its original typeparams.
|
||||
recvType = recvType.OrigSym().Def.(*ir.Name).Type()
|
||||
}
|
||||
tparams = recvType.RParams()
|
||||
} else {
|
||||
fields := nameNode.Type().TParams().Fields().Slice()
|
||||
@ -656,11 +662,9 @@ func (g *genInst) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMe
|
||||
s1 := make([]*types.Type, len(shapes))
|
||||
for i, t := range shapes {
|
||||
var tparam *types.Type
|
||||
if tparams[i].Kind() == types.TTYPEPARAM {
|
||||
// Shapes are grouped differently for structural types, so we
|
||||
// pass the type param to Shapify(), so we can distinguish.
|
||||
tparam = tparams[i]
|
||||
}
|
||||
if !t.IsShape() {
|
||||
s1[i] = typecheck.Shapify(t, i, tparam)
|
||||
} else {
|
||||
@ -1055,8 +1059,6 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
||||
// Transform the conversion, now that we know the
|
||||
// type argument.
|
||||
m = transformConvCall(call)
|
||||
// CONVIFACE transformation was already done in noder2
|
||||
assert(m.Op() != ir.OCONVIFACE)
|
||||
|
||||
case ir.OMETHVALUE, ir.OMETHEXPR:
|
||||
// Redo the transformation of OXDOT, now that we
|
||||
@ -1076,14 +1078,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
||||
case ir.ONAME:
|
||||
name := call.X.Name()
|
||||
if name.BuiltinOp != ir.OXXX {
|
||||
switch name.BuiltinOp {
|
||||
case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
|
||||
// Transform these builtins now that we
|
||||
// know the type of the args.
|
||||
m = transformBuiltin(call)
|
||||
default:
|
||||
base.FatalfAt(call.Pos(), "Unexpected builtin op")
|
||||
}
|
||||
} else {
|
||||
// This is the case of a function value that was a
|
||||
// type parameter (implied to be a function via a
|
||||
@ -1154,6 +1149,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
||||
newfn.Dcl = append(newfn.Dcl, ldict)
|
||||
as := ir.NewAssignStmt(x.Pos(), ldict, cdict)
|
||||
as.SetTypecheck(1)
|
||||
ldict.Defn = as
|
||||
newfn.Body.Append(as)
|
||||
|
||||
// Create inst info for the instantiated closure. The dict
|
||||
@ -1183,6 +1179,26 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
||||
subst.g.newInsts = append(subst.g.newInsts, m.(*ir.ClosureExpr).Func)
|
||||
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
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ func transformCompare(n *ir.BinaryExpr) {
|
||||
aop, _ := typecheck.Assignop(rt, lt)
|
||||
if aop != ir.OXXX {
|
||||
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.SetTypecheck(1)
|
||||
}
|
||||
|
@ -1338,10 +1338,10 @@ func (w *writer) compLit(lit *syntax.CompositeLit) {
|
||||
w.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()
|
||||
}
|
||||
str, isStruct := types2.StructuralType(typ).(*types2.Struct)
|
||||
str, isStruct := types2.CoreType(typ).(*types2.Struct)
|
||||
|
||||
w.len(len(lit.ElemList))
|
||||
for i, elem := range lit.ElemList {
|
||||
|
@ -1457,7 +1457,7 @@ func WriteBasicTypes() {
|
||||
|
||||
type typeAndStr struct {
|
||||
t *types.Type
|
||||
short string // "short" here means NameString
|
||||
short string // "short" here means TypeSymName
|
||||
regular string
|
||||
}
|
||||
|
||||
|
@ -256,7 +256,7 @@
|
||||
(Leq64F ...) => (FLED ...)
|
||||
(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))
|
||||
(Eq32 x y) => (SEQZ (SUB <x.Type> (ZeroExt32to64 x) (ZeroExt32to64 y)))
|
||||
(Eq16 x y) => (SEQZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y)))
|
||||
@ -264,7 +264,7 @@
|
||||
(Eq64F ...) => (FEQD ...)
|
||||
(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))
|
||||
(Neq32 x y) => (SNEZ (SUB <x.Type> (ZeroExt32to64 x) (ZeroExt32to64 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)
|
||||
}
|
||||
|
||||
// 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
|
||||
// to tell.
|
||||
// Complexity is O(n).
|
||||
|
@ -1124,13 +1124,14 @@ func rewriteValueRISCV64_OpEqPtr(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
typ := &b.Func.Config.Types
|
||||
// match: (EqPtr x y)
|
||||
// result: (SEQZ (SUB <x.Type> x y))
|
||||
// result: (SEQZ (SUB <typ.Uintptr> x y))
|
||||
for {
|
||||
x := v_0
|
||||
y := v_1
|
||||
v.reset(OpRISCV64SEQZ)
|
||||
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
|
||||
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, typ.Uintptr)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
@ -2673,13 +2674,14 @@ func rewriteValueRISCV64_OpNeqPtr(v *Value) bool {
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
typ := &b.Func.Config.Types
|
||||
// match: (NeqPtr x y)
|
||||
// result: (SNEZ (SUB <x.Type> x y))
|
||||
// result: (SNEZ (SUB <typ.Uintptr> x y))
|
||||
for {
|
||||
x := v_0
|
||||
y := v_1
|
||||
v.reset(OpRISCV64SNEZ)
|
||||
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
|
||||
v0 := b.NewValue0(v.Pos, OpRISCV64SUB, typ.Uintptr)
|
||||
v0.AddArg2(x, y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
|
@ -6768,6 +6768,34 @@ func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym {
|
||||
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.
|
||||
func genssa(f *ssa.Func, pp *objw.Progs) {
|
||||
var s State
|
||||
@ -6790,6 +6818,8 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
|
||||
p.To.Sym = openDeferInfo
|
||||
}
|
||||
|
||||
emitWrappedFuncInfo(e, pp)
|
||||
|
||||
// Remember where each block starts.
|
||||
s.bstart = make([]*obj.Prog, f.NumBlocks())
|
||||
s.pp = pp
|
||||
|
@ -6,7 +6,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"./mysort"
|
||||
"cmd/compile/internal/test/testdata/mysort"
|
||||
)
|
||||
|
||||
type MyString struct {
|
||||
|
@ -1851,7 +1851,10 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||
n := n.(*ir.ClosureExpr)
|
||||
w.op(ir.OCLOSURE)
|
||||
w.pos(n.Pos())
|
||||
old := w.currPkg
|
||||
w.setPkg(n.Type().Pkg(), true)
|
||||
w.signature(n.Type())
|
||||
w.setPkg(old, true)
|
||||
|
||||
// Write out id for the Outer of each conditional variable. The
|
||||
// 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.
|
||||
n := importtype(pos, sym)
|
||||
t := n.Type()
|
||||
|
||||
// Because of recursion, we need to defer width calculations and
|
||||
// instantiations on intermediate types until the top-level type is
|
||||
// fully constructed. Note that we can have recursion via type
|
||||
// constraints.
|
||||
types.DeferCheckSize()
|
||||
deferDoInst()
|
||||
if tag == 'U' {
|
||||
rparams := r.typeList()
|
||||
t.SetRParams(rparams)
|
||||
}
|
||||
|
||||
// We also need to defer width calculations until
|
||||
// after the underlying type has been assigned.
|
||||
types.DeferCheckSize()
|
||||
deferDoInst()
|
||||
underlying := r.typ()
|
||||
t.SetUnderlying(underlying)
|
||||
|
||||
@ -1371,7 +1374,9 @@ func (r *importReader) node() ir.Node {
|
||||
case ir.OCLOSURE:
|
||||
//println("Importing CLOSURE")
|
||||
pos := r.pos()
|
||||
r.setPkg()
|
||||
typ := r.signature(nil, nil)
|
||||
r.setPkg()
|
||||
|
||||
// All the remaining code below is similar to (*noder).funcLit(), but
|
||||
// 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, "[")]
|
||||
}
|
||||
|
||||
// getShapes appends the list of the shape types that are used within type t to
|
||||
// listp. The type traversal is simplified for two reasons: (1) we can always stop a
|
||||
// type traversal when t.HasShape() is false; and (2) shape types can't appear inside
|
||||
// a named type, except for the type args of a generic type. So, the traversal will
|
||||
// always stop before we have to deal with recursive types.
|
||||
func getShapes(t *types.Type, listp *[]*types.Type) {
|
||||
if !t.HasShape() {
|
||||
return
|
||||
}
|
||||
if t.IsShape() {
|
||||
*listp = append(*listp, t)
|
||||
return
|
||||
}
|
||||
|
||||
if t.Sym() != nil {
|
||||
// A named type can't have shapes in it, except for type args of a
|
||||
// generic type. We will have to deal with this differently once we
|
||||
// alloc local types in generic functions (#47631).
|
||||
for _, rparam := range t.RParams() {
|
||||
getShapes(rparam, listp)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch t.Kind() {
|
||||
case types.TARRAY, types.TPTR, types.TSLICE, types.TCHAN:
|
||||
getShapes(t.Elem(), listp)
|
||||
|
||||
case types.TSTRUCT:
|
||||
for _, f := range t.FieldSlice() {
|
||||
getShapes(f.Type, listp)
|
||||
}
|
||||
|
||||
case types.TFUNC:
|
||||
for _, f := range t.Recvs().FieldSlice() {
|
||||
getShapes(f.Type, listp)
|
||||
}
|
||||
for _, f := range t.Params().FieldSlice() {
|
||||
getShapes(f.Type, listp)
|
||||
}
|
||||
for _, f := range t.Results().FieldSlice() {
|
||||
getShapes(f.Type, listp)
|
||||
}
|
||||
for _, f := range t.TParams().FieldSlice() {
|
||||
getShapes(f.Type, listp)
|
||||
}
|
||||
|
||||
case types.TINTER:
|
||||
for _, f := range t.Methods().Slice() {
|
||||
getShapes(f.Type, listp)
|
||||
}
|
||||
|
||||
case types.TMAP:
|
||||
getShapes(t.Key(), listp)
|
||||
getShapes(t.Elem(), listp)
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("Bad type in getShapes: %v", t.Kind()))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Shapify takes a concrete type and a type param index, and returns a GCshape type that can
|
||||
// be used in place of the input type and still generate identical code.
|
||||
// No methods are added - all methods calls directly on a shape should
|
||||
@ -1432,9 +1494,9 @@ func genericTypeName(sym *types.Sym) string {
|
||||
// For now, we only consider two types to have the same shape, if they have exactly
|
||||
// the same underlying type or they are both pointer types.
|
||||
//
|
||||
// tparam is the associated typeparam. If there is a structural type for
|
||||
// the associated type param (not common), then a pointer type t is mapped to its
|
||||
// underlying type, rather than being merged with other pointers.
|
||||
// tparam is the associated typeparam - it must be TTYPEPARAM type. If there is a
|
||||
// structural type for the associated type param (not common), then a pointer type t
|
||||
// is mapped to its underlying type, rather than being merged with other pointers.
|
||||
//
|
||||
// Shape types are also distinguished by the index of the type in a type param/arg
|
||||
// list. We need to do this so we can distinguish and substitute properly for two
|
||||
@ -1442,6 +1504,30 @@ func genericTypeName(sym *types.Sym) string {
|
||||
// instantiation.
|
||||
func Shapify(t *types.Type, index int, tparam *types.Type) *types.Type {
|
||||
assert(!t.IsShape())
|
||||
if t.HasShape() {
|
||||
// We are sometimes dealing with types from a shape instantiation
|
||||
// that were constructed from existing shape types, so t may
|
||||
// sometimes have shape types inside it. In that case, we find all
|
||||
// those shape types with getShapes() and replace them with their
|
||||
// underlying type.
|
||||
//
|
||||
// If we don't do this, we may create extra unneeded shape types that
|
||||
// have these other shape types embedded in them. This may lead to
|
||||
// generating extra shape instantiations, and a mismatch between the
|
||||
// instantiations that we used in generating dictionaries and the
|
||||
// instantations that are actually called. (#51303).
|
||||
list := []*types.Type{}
|
||||
getShapes(t, &list)
|
||||
list2 := make([]*types.Type, len(list))
|
||||
for i, shape := range list {
|
||||
list2[i] = shape.Underlying()
|
||||
}
|
||||
ts := Tsubster{
|
||||
Tparams: list,
|
||||
Targs: list2,
|
||||
}
|
||||
t = ts.Typ(t)
|
||||
}
|
||||
// Map all types with the same underlying type to the same shape.
|
||||
u := t.Underlying()
|
||||
|
||||
|
@ -72,6 +72,7 @@ const (
|
||||
fmtDebug
|
||||
fmtTypeID
|
||||
fmtTypeIDName
|
||||
fmtTypeIDHash
|
||||
)
|
||||
|
||||
// Sym
|
||||
@ -144,10 +145,21 @@ func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
|
||||
if q := pkgqual(s.Pkg, verb, mode); q != "" {
|
||||
b.WriteString(q)
|
||||
b.WriteByte('.')
|
||||
if mode == fmtTypeIDName {
|
||||
switch mode {
|
||||
case fmtTypeIDName:
|
||||
// If name is a generic instantiation, it might have local package placeholders
|
||||
// in it. Replace those placeholders with the package name. See issue 49547.
|
||||
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)
|
||||
@ -173,7 +185,7 @@ func pkgqual(pkg *Pkg, verb rune, mode fmtMode) string {
|
||||
case fmtDebug:
|
||||
return pkg.Name
|
||||
|
||||
case fmtTypeIDName:
|
||||
case fmtTypeIDName, fmtTypeIDHash:
|
||||
// dcommontype, typehash
|
||||
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 {
|
||||
// in %-T mode collapse predeclared aliases with their originals.
|
||||
switch mode {
|
||||
case fmtTypeIDName, fmtTypeID:
|
||||
case fmtTypeIDName, fmtTypeIDHash, fmtTypeID:
|
||||
t = Types[t.Kind()]
|
||||
default:
|
||||
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:
|
||||
b.WriteByte('*')
|
||||
switch mode {
|
||||
case fmtTypeID, fmtTypeIDName:
|
||||
case fmtTypeID, fmtTypeIDName, fmtTypeIDHash:
|
||||
if verb == 'S' {
|
||||
tconv2(b, t.Elem(), 'S', mode, visited)
|
||||
return
|
||||
@ -484,7 +496,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
|
||||
case IsExported(f.Sym.Name):
|
||||
sconv2(b, f.Sym, 'S', mode)
|
||||
default:
|
||||
if mode != fmtTypeIDName {
|
||||
if mode != fmtTypeIDName && mode != fmtTypeIDHash {
|
||||
mode = fmtTypeID
|
||||
}
|
||||
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))
|
||||
fieldVerb := 'v'
|
||||
switch mode {
|
||||
case fmtTypeID, fmtTypeIDName, fmtGo:
|
||||
case fmtTypeID, fmtTypeIDName, fmtTypeIDHash, fmtGo:
|
||||
// no argument names on function signature, and no "noescape"/"nosplit" tags
|
||||
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
|
||||
// the field name when embedding f.Type.
|
||||
// TODO(mdempsky): Check for other occurences of this logic
|
||||
// TODO(mdempsky): Check for other occurrences of this logic
|
||||
// and deduplicate.
|
||||
typ := f.Type
|
||||
if typ.IsPtr() {
|
||||
@ -688,7 +700,7 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
|
||||
if name == ".F" {
|
||||
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)
|
||||
}
|
||||
} 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.
|
||||
func TypeHash(t *Type) uint32 {
|
||||
p := t.NameString()
|
||||
p := tconv(t, 0, fmtTypeIDHash)
|
||||
|
||||
// Using MD5 is overkill, but reduces accidental collisions.
|
||||
h := md5.Sum([]byte(p))
|
||||
|
@ -204,12 +204,12 @@ type Info struct {
|
||||
// qualified identifiers are collected in the Uses map.
|
||||
Types map[syntax.Expr]TypeAndValue
|
||||
|
||||
// Instances maps identifiers denoting parameterized types or functions to
|
||||
// their type arguments and instantiated type.
|
||||
// Instances maps identifiers denoting generic types or functions to their
|
||||
// type arguments and instantiated type.
|
||||
//
|
||||
// For example, Instances will map the identifier for 'T' in the type
|
||||
// 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
|
||||
// expression F(int(1)) to the inferred type arguments [int], and resulting
|
||||
// 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.
|
||||
//
|
||||
// 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 {
|
||||
m, _ := (*Checker)(nil).assertableTo(V, T)
|
||||
return m == nil
|
||||
// Checker.newAssertableTo suppresses errors for invalid types, so we need special
|
||||
// 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 {
|
||||
x := operand{mode: value, typ: V}
|
||||
ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x
|
||||
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 {
|
||||
x := operand{mode: value, typ: V}
|
||||
return x.convertibleTo(nil, T, nil) // check not needed for non-constant x
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if T.Empty() {
|
||||
// All types (even Typ[Invalid]) implement the empty interface.
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"internal/testenv"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -403,69 +404,61 @@ func TestTypesInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInstanceInfo(t *testing.T) {
|
||||
var tests = []struct {
|
||||
src string
|
||||
const lib = `package lib
|
||||
|
||||
func F[P any](P) {}
|
||||
|
||||
type T[P any] []P
|
||||
`
|
||||
|
||||
type testInst struct {
|
||||
name string
|
||||
targs []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) }`,
|
||||
`f`,
|
||||
[]string{`int`},
|
||||
`func(int)`,
|
||||
[]testInst{{`f`, []string{`int`}, `func(int)`}},
|
||||
},
|
||||
{`package p1; func f[T any](T) T { panic(0) }; func _() { f('@') }`,
|
||||
`f`,
|
||||
[]string{`rune`},
|
||||
`func(rune) rune`,
|
||||
[]testInst{{`f`, []string{`rune`}, `func(rune) rune`}},
|
||||
},
|
||||
{`package p2; func f[T any](...T) T { panic(0) }; func _() { f(0i) }`,
|
||||
`f`,
|
||||
[]string{`complex128`},
|
||||
`func(...complex128) complex128`,
|
||||
[]testInst{{`f`, []string{`complex128`}, `func(...complex128) complex128`}},
|
||||
},
|
||||
{`package p3; func f[A, B, C any](A, *B, []C) {}; func _() { f(1.2, new(string), []byte{}) }`,
|
||||
`f`,
|
||||
[]string{`float64`, `string`, `byte`},
|
||||
`func(float64, *string, []byte)`,
|
||||
[]testInst{{`f`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`}},
|
||||
},
|
||||
{`package p4; func f[A, B any](A, *B, ...[]B) {}; func _() { f(1.2, new(byte)) }`,
|
||||
`f`,
|
||||
[]string{`float64`, `byte`},
|
||||
`func(float64, *byte, ...[]byte)`,
|
||||
[]testInst{{`f`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`}},
|
||||
},
|
||||
|
||||
// we don't know how to translate these but we can type-check them
|
||||
{`package q0; type T struct{}; func (T) m[P any](P) {}; func _(x T) { x.m(42) }`,
|
||||
`m`,
|
||||
[]string{`int`},
|
||||
`func(int)`,
|
||||
[]testInst{{`m`, []string{`int`}, `func(int)`}},
|
||||
},
|
||||
{`package q1; type T struct{}; func (T) m[P any](P) P { panic(0) }; func _(x T) { x.m(42) }`,
|
||||
`m`,
|
||||
[]string{`int`},
|
||||
`func(int) int`,
|
||||
[]testInst{{`m`, []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) }`,
|
||||
`m`,
|
||||
[]string{`int`},
|
||||
`func(...int) int`,
|
||||
[]testInst{{`m`, []string{`int`}, `func(...int) int`}},
|
||||
},
|
||||
{`package q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C) {}; func _(x T) { x.m(1.2, new(string), []byte{}) }`,
|
||||
`m`,
|
||||
[]string{`float64`, `string`, `byte`},
|
||||
`func(float64, *string, []byte)`,
|
||||
[]testInst{{`m`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`}},
|
||||
},
|
||||
{`package q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B) {}; func _(x T) { x.m(1.2, new(byte)) }`,
|
||||
`m`,
|
||||
[]string{`float64`, `byte`},
|
||||
`func(float64, *byte, ...[]byte)`,
|
||||
[]testInst{{`m`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`}},
|
||||
},
|
||||
|
||||
{`package r0; type T[P any] struct{}; func (_ T[P]) m[Q any](Q) {}; func _[P any](x T[P]) { x.m(42) }`,
|
||||
`m`,
|
||||
[]string{`int`},
|
||||
`func(int)`,
|
||||
{`package r0; type T[P1 any] struct{}; func (_ T[P2]) m[Q any](Q) {}; func _[P3 any](x T[P3]) { x.m(42) }`,
|
||||
[]testInst{
|
||||
{`T`, []string{`P2`}, `struct{}`},
|
||||
{`T`, []string{`P3`}, `struct{}`},
|
||||
{`m`, []string{`int`}, `func(int)`},
|
||||
},
|
||||
},
|
||||
// TODO(gri) record method type parameters in syntax.FuncType so we can check this
|
||||
// {`package r1; type T interface{ m[P any](P) }; func _(x T) { x.m(4.2) }`,
|
||||
@ -474,97 +467,113 @@ func TestInstanceInfo(t *testing.T) {
|
||||
// `func(float64)`,
|
||||
// },
|
||||
|
||||
{`package s1; func f[T any, P interface{~*T}](x T) {}; func _(x string) { f(x) }`,
|
||||
`f`,
|
||||
[]string{`string`, `*string`},
|
||||
`func(x string)`,
|
||||
{`package s1; func f[T any, P interface{*T}](x T) {}; func _(x string) { f(x) }`,
|
||||
[]testInst{{`f`, []string{`string`, `*string`}, `func(x string)`}},
|
||||
},
|
||||
{`package s2; func f[T any, P interface{~*T}](x []T) {}; func _(x []int) { f(x) }`,
|
||||
`f`,
|
||||
[]string{`int`, `*int`},
|
||||
`func(x []int)`,
|
||||
{`package s2; func f[T any, P interface{*T}](x []T) {}; func _(x []int) { f(x) }`,
|
||||
[]testInst{{`f`, []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) }`,
|
||||
`f`,
|
||||
[]string{`int`, `chan<- 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) }`,
|
||||
[]testInst{
|
||||
{`C`, []string{`T`}, `interface{chan<- T}`},
|
||||
{`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) }`,
|
||||
[]testInst{
|
||||
{`C`, []string{`T`}, `interface{chan<- T}`},
|
||||
{`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
|
||||
{`f`, []string{`int`, `chan<- int`, `chan<- []*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) }`,
|
||||
`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] }`,
|
||||
`f`,
|
||||
[]string{`string`, `*string`},
|
||||
`func() string`,
|
||||
{`package t1; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = f[string] }`,
|
||||
[]testInst{{`f`, []string{`string`, `*string`}, `func() string`}},
|
||||
},
|
||||
{`package t2; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = (f[string]) }`,
|
||||
`f`,
|
||||
[]string{`string`, `*string`},
|
||||
`func() string`,
|
||||
{`package t2; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = (f[string]) }`,
|
||||
[]testInst{{`f`, []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] }`,
|
||||
`f`,
|
||||
[]string{`int`, `chan<- int`, `chan<- []*chan<- int`},
|
||||
`func() []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] }`,
|
||||
[]testInst{
|
||||
{`C`, []string{`T`}, `interface{chan<- T}`},
|
||||
{`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] }`,
|
||||
`f`,
|
||||
[]string{`int`, `chan<- int`, `chan<- []*chan<- int`},
|
||||
`func() []int`,
|
||||
},
|
||||
{`package i0; import lib "generic_lib"; func _() { lib.F(42) }`,
|
||||
`F`,
|
||||
[]string{`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]) }`,
|
||||
[]testInst{
|
||||
{`C`, []string{`T`}, `interface{chan<- T}`},
|
||||
{`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
|
||||
{`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`},
|
||||
},
|
||||
},
|
||||
{`package i0; import "lib"; func _() { lib.F(42) }`,
|
||||
[]testInst{{`F`, []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]`,
|
||||
`T`,
|
||||
[]string{`int`},
|
||||
`struct{x int}`,
|
||||
[]testInst{{`T`, []string{`int`}, `struct{x int}`}},
|
||||
},
|
||||
{`package type1; type T[P interface{~int}] struct{ x P }; var _ (T[int])`,
|
||||
`T`,
|
||||
[]string{`int`},
|
||||
`struct{x int}`,
|
||||
[]testInst{{`T`, []string{`int`}, `struct{x int}`}},
|
||||
},
|
||||
{`package type2; type T[P interface{~int}] struct{ x P }; var _ T[(int)]`,
|
||||
`T`,
|
||||
[]string{`int`},
|
||||
`struct{x int}`,
|
||||
[]testInst{{`T`, []string{`int`}, `struct{x int}`}},
|
||||
},
|
||||
{`package type3; type T[P1 interface{~[]P2}, P2 any] struct{ x P1; y P2 }; var _ T[[]int, int]`,
|
||||
`T`,
|
||||
[]string{`[]int`, `int`},
|
||||
`struct{x []int; y int}`,
|
||||
[]testInst{{`T`, []string{`[]int`, `int`}, `struct{x []int; y int}`}},
|
||||
},
|
||||
{`package type4; import "lib"; var _ lib.T[int]`,
|
||||
[]testInst{{`T`, []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`},
|
||||
},
|
||||
{`package type4; import lib "generic_lib"; var _ lib.T[int]`,
|
||||
`T`,
|
||||
[]string{`int`},
|
||||
`[]int`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
const lib = `package generic_lib
|
||||
|
||||
func F[P any](P) {}
|
||||
|
||||
type T[P any] []P
|
||||
`
|
||||
|
||||
imports := make(testImporter)
|
||||
conf := Config{Importer: imports}
|
||||
instances := make(map[*syntax.Name]Instance)
|
||||
uses := make(map[*syntax.Name]Object)
|
||||
instMap := make(map[*syntax.Name]Instance)
|
||||
useMap := make(map[*syntax.Name]Object)
|
||||
makePkg := func(src string) *Package {
|
||||
f, err := parseSrc("p.go", src)
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -574,58 +583,70 @@ type T[P any] []P
|
||||
makePkg(lib)
|
||||
pkg := makePkg(test.src)
|
||||
|
||||
// look for instance information
|
||||
var targs []Type
|
||||
var typ Type
|
||||
for ident, inst := range instances {
|
||||
if syntax.String(ident) == test.name {
|
||||
for i := 0; i < inst.TypeArgs.Len(); i++ {
|
||||
targs = append(targs, inst.TypeArgs.At(i))
|
||||
t.Run(pkg.Name(), func(t *testing.T) {
|
||||
// Sort instances in source order for stability.
|
||||
instances := sortedInstances(instMap)
|
||||
if got, want := len(instances), len(test.instances); got != want {
|
||||
t.Fatalf("got %d instances, want %d", got, want)
|
||||
}
|
||||
typ = inst.Type
|
||||
|
||||
// Check that we can find the corresponding parameterized type.
|
||||
ptype := uses[ident].Type()
|
||||
// Pairwise compare with the expected instances.
|
||||
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 })
|
||||
if lister == nil || lister.TypeParams().Len() == 0 {
|
||||
t.Errorf("package %s: info.Types[%v] = %v, want parameterized type", pkg.Name(), ident, ptype)
|
||||
continue
|
||||
t.Fatalf("info.Types[%v] = %v, want parameterized type", inst.Name, ptype)
|
||||
}
|
||||
|
||||
// Verify the invariant that re-instantiating the generic type with
|
||||
// TypeArgs results in an equivalent type.
|
||||
inst2, err := Instantiate(nil, ptype, targs, true)
|
||||
if err != nil {
|
||||
t.Errorf("Instantiate(%v, %v) failed: %v", ptype, targs, err)
|
||||
}
|
||||
if !Identical(inst.Type, inst2) {
|
||||
t.Errorf("%v and %v are not identical", inst.Type, inst2)
|
||||
}
|
||||
break
|
||||
if !Identical(inst.Inst.Type, inst2) {
|
||||
t.Errorf("%v and %v are not identical", inst.Inst.Type, inst2)
|
||||
}
|
||||
}
|
||||
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) {
|
||||
@ -1697,7 +1718,7 @@ func F(){
|
||||
var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F
|
||||
|
||||
var a []int
|
||||
for i, x := range /*i=undef*/ /*x=var:16*/ a /*i=var:20*/ /*x=var:20*/ { _ = i; _ = x }
|
||||
for i, x := range a /*i=undef*/ /*x=var:16*/ { _ = i; _ = x }
|
||||
|
||||
var i interface{}
|
||||
switch y := i.(type) { /*y=undef*/
|
||||
@ -2313,27 +2334,27 @@ type Bad Bad // invalid type
|
||||
conf := Config{Error: func(error) {}}
|
||||
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 (
|
||||
EmptyIface = scope.Lookup("EmptyIface").Type().Underlying().(*Interface)
|
||||
I = scope.Lookup("I").Type().(*Named)
|
||||
EmptyIface = lookup("EmptyIface").Underlying().(*Interface)
|
||||
I = lookup("I").(*Named)
|
||||
II = I.Underlying().(*Interface)
|
||||
C = scope.Lookup("C").Type().(*Named)
|
||||
C = lookup("C").(*Named)
|
||||
CI = C.Underlying().(*Interface)
|
||||
Integer = scope.Lookup("Integer").Type().Underlying().(*Interface)
|
||||
EmptyTypeSet = scope.Lookup("EmptyTypeSet").Type().Underlying().(*Interface)
|
||||
N1 = scope.Lookup("N1").Type()
|
||||
Integer = lookup("Integer").Underlying().(*Interface)
|
||||
EmptyTypeSet = lookup("EmptyTypeSet").Underlying().(*Interface)
|
||||
N1 = lookup("N1")
|
||||
N1p = NewPointer(N1)
|
||||
N2 = scope.Lookup("N2").Type()
|
||||
N2 = lookup("N2")
|
||||
N2p = NewPointer(N2)
|
||||
N3 = scope.Lookup("N3").Type()
|
||||
N4 = scope.Lookup("N4").Type()
|
||||
Bad = scope.Lookup("Bad").Type()
|
||||
N3 = lookup("N3")
|
||||
N4 = lookup("N4")
|
||||
Bad = lookup("Bad")
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
t Type
|
||||
i *Interface
|
||||
V Type
|
||||
T *Interface
|
||||
want bool
|
||||
}{
|
||||
{I, II, true},
|
||||
@ -2364,8 +2385,20 @@ type Bad Bad // invalid type
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
if got := Implements(test.t, test.i); got != test.want {
|
||||
t.Errorf("Implements(%s, %s) = %t, want %t", 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.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, ", ") + ")"
|
||||
}
|
||||
|
||||
func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) {
|
||||
measure := func(x int, unit string) string {
|
||||
s := fmt.Sprintf("%d %s", x, unit)
|
||||
func measure(x int, unit string) string {
|
||||
if x != 1 {
|
||||
s += "s"
|
||||
unit += "s"
|
||||
}
|
||||
return s
|
||||
return fmt.Sprintf("%d %s", x, unit)
|
||||
}
|
||||
|
||||
func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) {
|
||||
vars := measure(nvars, "variable")
|
||||
vals := measure(nvals, "value")
|
||||
rhs0 := rhs[0]
|
||||
|
@ -82,10 +82,24 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||
// of S and the respective parameter passing rules apply."
|
||||
S := x.typ
|
||||
var T Type
|
||||
if s, _ := structuralType(S).(*Slice); s != nil {
|
||||
if s, _ := coreType(S).(*Slice); s != nil {
|
||||
T = s.elem
|
||||
} 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
|
||||
}
|
||||
|
||||
@ -101,7 +115,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||
if x.mode == invalid {
|
||||
return
|
||||
}
|
||||
if t := structuralString(x.typ); t != nil && isString(t) {
|
||||
if t := coreString(x.typ); t != nil && isString(t) {
|
||||
if check.Types != nil {
|
||||
sig := makeSig(S, S, x.typ)
|
||||
sig.variadic = true
|
||||
@ -331,14 +345,14 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||
|
||||
case _Copy:
|
||||
// copy(x, y []T) int
|
||||
dst, _ := structuralType(x.typ).(*Slice)
|
||||
dst, _ := coreType(x.typ).(*Slice)
|
||||
|
||||
var y operand
|
||||
arg(&y, 1)
|
||||
if y.mode == invalid {
|
||||
return
|
||||
}
|
||||
src0 := structuralString(y.typ)
|
||||
src0 := coreString(y.typ)
|
||||
if src0 != nil && isString(src0) {
|
||||
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
|
||||
switch structuralType(T).(type) {
|
||||
switch coreType(T).(type) {
|
||||
case *Slice:
|
||||
min = 2
|
||||
case *Map, *Chan:
|
||||
min = 1
|
||||
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
|
||||
default:
|
||||
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
|
||||
|
||||
// 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 {
|
||||
check.errorf(x, invalidOp+"cannot call non-function %s", x)
|
||||
x.mode = invalid
|
||||
@ -423,7 +423,7 @@ var cgoPrefixes = [...]string{
|
||||
"_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
|
||||
var (
|
||||
obj Object
|
||||
@ -525,7 +525,17 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -18,19 +18,6 @@ var nopos syntax.Pos
|
||||
// debugging/development support
|
||||
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.
|
||||
type exprInfo struct {
|
||||
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
|
||||
delayed []action // stack of delayed action segments; segments are processed in FIFO order
|
||||
objPath []Object // path of object dependencies during type inference (for cycle reporting)
|
||||
defTypes []*Named // defined types created during type checking, for final validation.
|
||||
cleaners []cleaner // list of types that may need a final cleanup at the end of type-checking
|
||||
|
||||
// environment within which the current object is type-checked (valid only
|
||||
// for the duration of type-checking a specific object)
|
||||
@ -218,6 +205,16 @@ func (check *Checker) pop() Object {
|
||||
return obj
|
||||
}
|
||||
|
||||
type cleaner interface {
|
||||
cleanup()
|
||||
}
|
||||
|
||||
// needsCleanup records objects/types that implement the cleanup method
|
||||
// which will be called at the end of type-checking.
|
||||
func (check *Checker) needsCleanup(c cleaner) {
|
||||
check.cleaners = append(check.cleaners, c)
|
||||
}
|
||||
|
||||
// NewChecker returns a new Checker instance for a given package.
|
||||
// Package files may be added incrementally via checker.Files.
|
||||
func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
|
||||
@ -260,6 +257,8 @@ func (check *Checker) initFiles(files []*syntax.File) {
|
||||
check.methods = nil
|
||||
check.untyped = nil
|
||||
check.delayed = nil
|
||||
check.objPath = nil
|
||||
check.cleaners = nil
|
||||
|
||||
// determine package name and collect valid files
|
||||
pkg := check.pkg
|
||||
@ -328,8 +327,8 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
|
||||
print("== processDelayed ==")
|
||||
check.processDelayed(0) // incl. all functions
|
||||
|
||||
print("== expandDefTypes ==")
|
||||
check.expandDefTypes()
|
||||
print("== cleanup ==")
|
||||
check.cleanup()
|
||||
|
||||
print("== initOrder ==")
|
||||
check.initOrder()
|
||||
@ -357,7 +356,6 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
|
||||
check.recvTParamMap = nil
|
||||
check.brokenAliases = nil
|
||||
check.unionTypeSets = nil
|
||||
check.defTypes = nil
|
||||
check.ctxt = nil
|
||||
|
||||
// TODO(gri) There's more memory we should release at this point.
|
||||
@ -385,27 +383,13 @@ func (check *Checker) processDelayed(top int) {
|
||||
check.delayed = check.delayed[:top]
|
||||
}
|
||||
|
||||
func (check *Checker) expandDefTypes() {
|
||||
// Ensure that every defined type created in the course of type-checking has
|
||||
// either non-*Named underlying, or is unresolved.
|
||||
//
|
||||
// This guarantees that we don't leak any types whose underlying is *Named,
|
||||
// because any unresolved instances will lazily compute their underlying by
|
||||
// substituting in the underlying of their origin. The origin must have
|
||||
// either been imported or type-checked and expanded here, and in either case
|
||||
// its underlying will be fully expanded.
|
||||
for i := 0; i < len(check.defTypes); i++ {
|
||||
n := check.defTypes[i]
|
||||
switch n.underlying.(type) {
|
||||
case nil:
|
||||
if n.resolver == nil {
|
||||
panic("nil underlying")
|
||||
}
|
||||
case *Named:
|
||||
n.under() // n.under may add entries to check.defTypes
|
||||
}
|
||||
n.check = nil
|
||||
// cleanup runs cleanup for all collected cleaners.
|
||||
func (check *Checker) cleanup() {
|
||||
// Don't use a range clause since Named.cleanup may add more cleaners.
|
||||
for i := 0; i < len(check.cleaners); i++ {
|
||||
check.cleaners[i].cleanup()
|
||||
}
|
||||
check.cleaners = nil
|
||||
}
|
||||
|
||||
func (check *Checker) record(x *operand) {
|
||||
|
@ -19,12 +19,12 @@ func AsSignature(t Type) *Signature {
|
||||
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
|
||||
// nil otherwise. If the type set contains only unrestricted and restricted
|
||||
// channel types (with identical element types), the single underlying type
|
||||
// is the restricted channel type if the restrictions are always the same.
|
||||
// If typ is not a type parameter, structuralType returns the underlying type.
|
||||
func StructuralType(t Type) Type {
|
||||
return structuralType(t)
|
||||
// If typ is not a type parameter, CoreType returns the underlying type.
|
||||
func CoreType(t Type) Type {
|
||||
return coreType(t)
|
||||
}
|
||||
|
@ -49,11 +49,14 @@ func (check *Checker) conversion(x *operand, T Type) {
|
||||
// have specific types, constant x cannot be
|
||||
// converted.
|
||||
ok = T.(*TypeParam).underIs(func(u Type) bool {
|
||||
// t is nil if there are no specific type terms
|
||||
// u is nil if there are no specific type terms
|
||||
if u == nil {
|
||||
cause = check.sprintf("%s does not contain specific types", T)
|
||||
return false
|
||||
}
|
||||
if isString(x.typ) && isBytesOrRunes(u) {
|
||||
return true
|
||||
}
|
||||
if !constConvertibleTo(u, nil) {
|
||||
cause = check.sprintf("cannot convert %s to %s (in %s)", x, u, T)
|
||||
return false
|
||||
|
@ -569,7 +569,6 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Fiel
|
||||
|
||||
// Keep track of bounds for later validation.
|
||||
var bound Type
|
||||
var bounds []Type
|
||||
for i, f := range list {
|
||||
// Optimization: Re-use the previous type bound if it hasn't changed.
|
||||
// This also preserves the grouped output of type parameter lists
|
||||
@ -584,7 +583,6 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Fiel
|
||||
check.error(f.Type, "cannot use a type parameter as constraint")
|
||||
bound = Typ[Invalid]
|
||||
}
|
||||
bounds = append(bounds, bound)
|
||||
}
|
||||
tparams[i].bound = bound
|
||||
}
|
||||
|
@ -124,6 +124,17 @@ func sprintf(qf Qualifier, debug bool, format string, args ...interface{}) strin
|
||||
}
|
||||
buf.WriteByte(']')
|
||||
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
|
||||
}
|
||||
|
@ -182,9 +182,9 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) {
|
||||
return
|
||||
|
||||
case syntax.Recv:
|
||||
u := structuralType(x.typ)
|
||||
u := coreType(x.typ)
|
||||
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
|
||||
return
|
||||
}
|
||||
@ -899,7 +899,7 @@ func (check *Checker) incomparableCause(typ Type) string {
|
||||
}
|
||||
// see if we can extract a more specific error
|
||||
var cause string
|
||||
comparable(typ, nil, func(format string, args ...interface{}) {
|
||||
comparable(typ, true, nil, func(format string, args ...interface{}) {
|
||||
cause = check.sprintf(format, args...)
|
||||
})
|
||||
return cause
|
||||
@ -1359,7 +1359,11 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||
case hint != nil:
|
||||
// no composite literal type present - use hint (element type of enclosing type)
|
||||
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:
|
||||
// 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
|
||||
}
|
||||
|
||||
switch utyp := structuralType(base).(type) {
|
||||
switch utyp := coreType(base).(type) {
|
||||
case *Struct:
|
||||
// Prevent crash if the struct referred to is not yet set up.
|
||||
// See analogous comment for *Array.
|
||||
@ -1552,7 +1556,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||
return kind
|
||||
|
||||
case *syntax.SelectorExpr:
|
||||
check.selector(x, e)
|
||||
check.selector(x, e, nil)
|
||||
|
||||
case *syntax.IndexExpr:
|
||||
if check.indexExpr(x, e) {
|
||||
@ -1638,6 +1642,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||
case invalid:
|
||||
goto Error
|
||||
case typexpr:
|
||||
check.validVarType(e.X, x.typ)
|
||||
x.typ = &Pointer{base: x.typ}
|
||||
default:
|
||||
var base Type
|
||||
|
@ -182,7 +182,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
|
||||
}
|
||||
|
||||
if !valid {
|
||||
check.errorf(x, invalidOp+"cannot index %s", x)
|
||||
check.errorf(e.Pos(), invalidOp+"cannot index %s", x)
|
||||
x.mode = invalid
|
||||
return false
|
||||
}
|
||||
@ -213,9 +213,9 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
|
||||
|
||||
valid := false
|
||||
length := int64(-1) // valid if >= 0
|
||||
switch u := structuralString(x.typ).(type) {
|
||||
switch u := coreString(x.typ).(type) {
|
||||
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
|
||||
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.
|
||||
n := len(tparams)
|
||||
assert(n > 0 && len(targs) <= n)
|
||||
@ -54,6 +61,64 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
|
||||
}
|
||||
// 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 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
|
||||
@ -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) {
|
||||
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
|
||||
// and the corresponding type arguments (which may be nil!).
|
||||
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.
|
||||
for _, tpar := range tparams {
|
||||
sbound := structuralType(tpar)
|
||||
if sbound != nil {
|
||||
// If the structural type is the underlying type of a single
|
||||
// defined type in the constraint, use that defined type instead.
|
||||
if named, _ := tpar.singleType().(*Named); named != nil {
|
||||
sbound = named
|
||||
// Repeatedly apply constraint type inference as long as
|
||||
// there are still unknown type arguments and progress is
|
||||
// being made.
|
||||
//
|
||||
// This is an O(n^2) algorithm where n is the number of
|
||||
// type parameters: if there is progress (and iteration
|
||||
// continues), at least one type argument is inferred
|
||||
// per iteration and we have a doubly nested loop.
|
||||
// In practice this is not a problem because the number
|
||||
// of type parameters tends to be very small (< 5 or so).
|
||||
// (It should be possible for unification to efficiently
|
||||
// signal newly inferred type arguments; then the loops
|
||||
// here could handle the respective type parameters only,
|
||||
// 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(tpar, sbound) {
|
||||
if !u.unify(tx, core.typ) {
|
||||
// TODO(gri) improve error message by providing the type arguments
|
||||
// which we know already
|
||||
check.errorf(pos, "%s does not match %s", tpar, sbound)
|
||||
// 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
|
||||
// arguments which were inferred from structural types. The newly inferred non-
|
||||
// nil entries may still contain references to other type parameters.
|
||||
// arguments which were inferred from core terms. The newly inferred non-nil
|
||||
// entries may still contain references to other type parameters.
|
||||
// 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
|
||||
// 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;
|
||||
// e.g., a structural constraint *P may match a type parameter Q but we
|
||||
// don't have any type arguments to fill in for *P or Q (issue #45548).
|
||||
// e.g., a constraint with core type *P may match a type parameter Q but
|
||||
// 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.
|
||||
for i, typ := range types {
|
||||
if typ != nil && isParameterized(tparams, typ) {
|
||||
@ -525,6 +658,42 @@ func (check *Checker) inferB(pos syntax.Pos, tparams []*TypeParam, targs []Type)
|
||||
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 {
|
||||
tparams []*TypeParam
|
||||
types []Type
|
||||
@ -570,8 +739,6 @@ func (w *cycleFinder) typ(typ Type) {
|
||||
// in signatures where they are handled explicitly.
|
||||
|
||||
case *Signature:
|
||||
// There are no "method types" so we should never see a recv.
|
||||
assert(t.recv == nil)
|
||||
if t.params != nil {
|
||||
w.varList(t.params.vars)
|
||||
}
|
||||
|
@ -15,10 +15,10 @@ import (
|
||||
|
||||
// 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
|
||||
// resulting Type is a new, instantiated (not parameterized) type of the same
|
||||
// kind (either a *Named or a *Signature). Methods attached to a *Named type
|
||||
// are also instantiated, and associated with a new *Func that has the same
|
||||
// position as the original method, but nil function scope.
|
||||
// resulting Type is an instantiated type of the same kind (either a *Named or
|
||||
// a *Signature). Methods attached to a *Named type are also instantiated, and
|
||||
// associated with a new *Func that has the same position as the original
|
||||
// method, but nil function scope.
|
||||
//
|
||||
// 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
|
||||
@ -204,7 +204,7 @@ func (check *Checker) implements(V, T Type) error {
|
||||
// If T is comparable, V must be comparable.
|
||||
// Remember as a pending error and report only if we don't have a more specific error.
|
||||
var pending error
|
||||
if Ti.IsComparable() && ((Vi != nil && !Vi.IsComparable()) || (Vi == nil && !Comparable(V))) {
|
||||
if Ti.IsComparable() && !comparable(V, false, nil, nil) {
|
||||
pending = errorf("%s does not implement comparable", V)
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
|
||||
}
|
||||
|
||||
// set method receivers if necessary
|
||||
typ := new(Interface)
|
||||
typ := (*Checker)(nil).newInterface()
|
||||
for _, m := range methods {
|
||||
if sig := m.typ.(*Signature); sig.recv == nil {
|
||||
sig.recv = NewVar(m.pos, m.pkg, "", typ)
|
||||
@ -54,6 +54,15 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
|
||||
return typ
|
||||
}
|
||||
|
||||
// check may be nil
|
||||
func (check *Checker) newInterface() *Interface {
|
||||
typ := &Interface{check: check}
|
||||
if check != nil {
|
||||
check.needsCleanup(typ)
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// MarkImplicit marks the interface t as implicit, meaning this interface
|
||||
// corresponds to a constraint literal such as ~T or A|B without explicit
|
||||
// interface embedding. MarkImplicit should be called before any concurrent use
|
||||
@ -100,6 +109,11 @@ func (t *Interface) String() string { return TypeString(t, nil) }
|
||||
// ----------------------------------------------------------------------------
|
||||
// Implementation
|
||||
|
||||
func (t *Interface) cleanup() {
|
||||
t.check = nil
|
||||
t.embedPos = nil
|
||||
}
|
||||
|
||||
func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType, def *Named) {
|
||||
addEmbedded := func(pos syntax.Pos, typ Type) {
|
||||
ityp.embeddeds = append(ityp.embeddeds, typ)
|
||||
@ -162,16 +176,10 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
|
||||
// (don't sort embeddeds: they must correspond to *embedPos entries)
|
||||
sortMethods(ityp.methods)
|
||||
|
||||
// Compute type set with a non-nil *Checker as soon as possible
|
||||
// to report any errors. Subsequent uses of type sets will use
|
||||
// this computed type set and won't need to pass in a *Checker.
|
||||
//
|
||||
// Pin the checker to the interface type in the interim, in case the type set
|
||||
// must be used before delayed funcs are processed (see issue #48234).
|
||||
// TODO(rfindley): clean up use of *Checker with computeInterfaceTypeSet
|
||||
ityp.check = check
|
||||
// Compute type set as soon as possible to report any errors.
|
||||
// Subsequent uses of type sets will use this computed type
|
||||
// set and won't need to pass in a *Checker.
|
||||
check.later(func() {
|
||||
computeInterfaceTypeSet(check, iface.Pos(), ityp)
|
||||
ityp.check = nil
|
||||
}).describef(iface, "compute type set for %s", ityp)
|
||||
}
|
||||
|
@ -66,12 +66,13 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
|
||||
|
||||
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,
|
||||
// see if there is a matching field (but not a method, those need to be declared explicitly
|
||||
// in the constraint). If the structural constraint is a named pointer type (see above), we
|
||||
// are ok here because only fields are accepted as results.
|
||||
if obj == nil && isTypeParam(T) {
|
||||
if t := structuralType(T); t != nil {
|
||||
// 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 in the constraint). If the constraint is a named pointer type (see
|
||||
// above), we are ok here because only fields are accepted as results.
|
||||
const enableTParamFieldLookup = false // see issue #51576
|
||||
if enableTParamFieldLookup && obj == nil && isTypeParam(T) {
|
||||
if t := coreType(T); t != nil {
|
||||
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false)
|
||||
if _, ok := obj.(*Var); !ok {
|
||||
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.
|
||||
// The receiver may be nil if assertableTo is invoked through an exported API call
|
||||
// (such as AssertableTo), i.e., when all methods have been type-checked.
|
||||
// If the global constant forceStrict is set, assertions that are known to fail
|
||||
// are not permitted.
|
||||
// TODO(gri) replace calls to this function with calls to newAssertableTo.
|
||||
func (check *Checker) assertableTo(V *Interface, T Type) (method, wrongType *Func) {
|
||||
// no static check is required if T is an interface
|
||||
// spec: "If T is an interface type, x.(T) asserts that the
|
||||
// dynamic type of x implements the interface T."
|
||||
if IsInterface(T) && !forceStrict {
|
||||
if IsInterface(T) {
|
||||
return
|
||||
}
|
||||
// TODO(gri) fix this for generalized interfaces
|
||||
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.
|
||||
// Otherwise it returns (typ, false).
|
||||
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.
|
||||
if check != nil {
|
||||
check.defTypes = append(check.defTypes, typ)
|
||||
check.needsCleanup(typ)
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
func (t *Named) cleanup() {
|
||||
// Ensure that every defined type created in the course of type-checking has
|
||||
// either non-*Named underlying, or is unresolved.
|
||||
//
|
||||
// This guarantees that we don't leak any types whose underlying is *Named,
|
||||
// because any unresolved instances will lazily compute their underlying by
|
||||
// substituting in the underlying of their origin. The origin must have
|
||||
// either been imported or type-checked and expanded here, and in either case
|
||||
// its underlying will be fully expanded.
|
||||
switch t.underlying.(type) {
|
||||
case nil:
|
||||
if t.resolver == nil {
|
||||
panic("nil underlying")
|
||||
}
|
||||
case *Named:
|
||||
t.under() // t.under may add entries to check.cleaners
|
||||
}
|
||||
t.check = nil
|
||||
}
|
||||
|
||||
// Obj returns the type name for the declaration defining the named type t. For
|
||||
// instantiated types, this is the type name of the base type.
|
||||
// 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
|
||||
|
||||
// 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.
|
||||
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.
|
||||
|
||||
// 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 }
|
||||
|
||||
// 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.
|
||||
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() }
|
||||
|
||||
// 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
|
||||
// *Interface before modifying receivers.
|
||||
if iface == n.orig.underlying {
|
||||
iface = &Interface{
|
||||
embeddeds: iface.embeddeds,
|
||||
complete: iface.complete,
|
||||
implicit: iface.implicit, // should be false but be conservative
|
||||
}
|
||||
old := iface
|
||||
iface = check.newInterface()
|
||||
iface.embeddeds = old.embeddeds
|
||||
iface.complete = old.complete
|
||||
iface.implicit = old.implicit // should be false but be conservative
|
||||
underlying = iface
|
||||
}
|
||||
iface.methods = methods
|
||||
|
@ -31,7 +31,7 @@ func isBasic(t Type, info BasicInfo) bool {
|
||||
// The allX predicates below report whether t is an X.
|
||||
// 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.
|
||||
// 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)).
|
||||
|
||||
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.
|
||||
// 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.
|
||||
// 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 {
|
||||
if tpar, _ := t.(*TypeParam); tpar != nil {
|
||||
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.
|
||||
func Comparable(T Type) bool {
|
||||
return comparable(T, nil, nil)
|
||||
return comparable(T, true, nil, nil)
|
||||
}
|
||||
|
||||
// If dynamic is set, non-type parameter interfaces are always comparable.
|
||||
// If reportf != nil, it may be used to report why T is not comparable.
|
||||
func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})) bool {
|
||||
func comparable(T Type, dynamic bool, seen map[Type]bool, reportf func(string, ...interface{})) bool {
|
||||
if seen[T] {
|
||||
return true
|
||||
}
|
||||
@ -124,7 +125,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
|
||||
return true
|
||||
case *Struct:
|
||||
for _, f := range t.fields {
|
||||
if !comparable(f.typ, seen, nil) {
|
||||
if !comparable(f.typ, dynamic, seen, nil) {
|
||||
if reportf != nil {
|
||||
reportf("struct containing %s cannot be compared", f.typ)
|
||||
}
|
||||
@ -133,7 +134,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
|
||||
}
|
||||
return true
|
||||
case *Array:
|
||||
if !comparable(t.elem, seen, nil) {
|
||||
if !comparable(t.elem, dynamic, seen, nil) {
|
||||
if reportf != nil {
|
||||
reportf("%s cannot be compared", t)
|
||||
}
|
||||
@ -141,7 +142,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
|
||||
}
|
||||
return true
|
||||
case *Interface:
|
||||
return !isTypeParam(T) || t.typeSet().IsComparable(seen)
|
||||
return dynamic && !isTypeParam(T) || t.typeSet().IsComparable(seen)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -413,7 +413,7 @@ func (check *Checker) collectObjects() {
|
||||
|
||||
case *syntax.TypeDecl:
|
||||
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)
|
||||
check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s})
|
||||
@ -458,7 +458,7 @@ func (check *Checker) collectObjects() {
|
||||
check.recordDef(s.Name, obj)
|
||||
}
|
||||
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}
|
||||
// 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.
|
||||
for i, p := range rparams {
|
||||
if p.Value == "_" {
|
||||
tpar := sig.rparams.At(i)
|
||||
if check.recvTParamMap == nil {
|
||||
check.recvTParamMap = make(map[*syntax.Name]*TypeParam)
|
||||
}
|
||||
check.recvTParamMap[p] = tpar
|
||||
check.recvTParamMap[p] = tparams[i]
|
||||
}
|
||||
}
|
||||
// determine receiver type to get its type parameters
|
||||
@ -136,22 +135,23 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
||||
}
|
||||
}
|
||||
// provide type parameter bounds
|
||||
// - only do this if we have the right number (otherwise an error is reported elsewhere)
|
||||
if sig.RecvTypeParams().Len() == len(recvTParams) {
|
||||
// We have a list of *TypeNames but we need a list of Types.
|
||||
list := make([]Type, sig.RecvTypeParams().Len())
|
||||
for i, t := range sig.RecvTypeParams().list() {
|
||||
list[i] = t
|
||||
check.mono.recordCanon(t, recvTParams[i])
|
||||
}
|
||||
smap := makeSubstMap(recvTParams, list)
|
||||
for i, tpar := range sig.RecvTypeParams().list() {
|
||||
bound := recvTParams[i].bound
|
||||
// bound is (possibly) parameterized in the context of the
|
||||
// receiver type declaration. Substitute parameters for the
|
||||
// current context.
|
||||
tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil)
|
||||
if len(tparams) == len(recvTParams) {
|
||||
smap := makeRenameMap(recvTParams, tparams)
|
||||
for i, tpar := range tparams {
|
||||
recvTPar := recvTParams[i]
|
||||
check.mono.recordCanon(tpar, recvTPar)
|
||||
// recvTPar.bound is (possibly) parameterized in the context of the
|
||||
// receiver type declaration. Substitute parameters for the current
|
||||
// context.
|
||||
tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil)
|
||||
}
|
||||
} else if len(tparams) < len(recvTParams) {
|
||||
// Reporting an error here is a stop-gap measure to avoid crashes in the
|
||||
// compiler when a type parameter/argument cannot be inferred later. It
|
||||
// may lead to follow-on errors (see issues #51339, #51343).
|
||||
// TODO(gri) find a better solution
|
||||
got := measure(len(tparams), "type parameter")
|
||||
check.errorf(recvPar, "got %s, but receiver base type declares %d", got, len(recvTParams))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -194,9 +194,11 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
||||
case 1:
|
||||
recv = recvList[0]
|
||||
}
|
||||
sig.recv = recv
|
||||
|
||||
// TODO(gri) We should delay rtyp expansion to when we actually need the
|
||||
// receiver; thus all checks here should be delayed to later.
|
||||
// Delay validation of receiver type as it may cause premature expansion
|
||||
// of types the receiver type is dependent on (see issues #51232, #51233).
|
||||
check.later(func() {
|
||||
rtyp, _ := deref(recv.typ)
|
||||
|
||||
// spec: "The receiver type must be of the form T or *T where T is a type name."
|
||||
@ -224,6 +226,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
||||
} 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:
|
||||
@ -250,10 +254,9 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
||||
}
|
||||
if err != "" {
|
||||
check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
|
||||
// ok to continue
|
||||
}
|
||||
}
|
||||
sig.recv = recv
|
||||
}).describef(recv, "validate receiver %s", recv)
|
||||
}
|
||||
|
||||
sig.params = NewTuple(params...)
|
||||
|
@ -409,9 +409,9 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
|
||||
if ch.mode == invalid || val.mode == invalid {
|
||||
return
|
||||
}
|
||||
u := structuralType(ch.typ)
|
||||
u := coreType(ch.typ)
|
||||
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
|
||||
}
|
||||
uch, _ := u.(*Chan)
|
||||
@ -626,14 +626,15 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
|
||||
|
||||
case *syntax.ForStmt:
|
||||
inner |= breakOk | continueOk
|
||||
check.openScope(s, "for")
|
||||
defer check.closeScope()
|
||||
|
||||
if rclause, _ := s.Init.(*syntax.RangeClause); rclause != nil {
|
||||
check.rangeStmt(inner, s, rclause)
|
||||
break
|
||||
}
|
||||
|
||||
check.openScope(s, "for")
|
||||
defer check.closeScope()
|
||||
|
||||
check.simpleStmt(s.Init)
|
||||
if s.Cond != nil {
|
||||
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) {
|
||||
// scope already opened
|
||||
|
||||
// determine lhs, if any
|
||||
sKey := rclause.Lhs // possibly nil
|
||||
var sValue, sExtra syntax.Expr
|
||||
@ -835,9 +834,9 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
|
||||
// determine key/value types
|
||||
var key, val Type
|
||||
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
|
||||
u := structuralType(x.typ)
|
||||
u := coreType(x.typ)
|
||||
if t, _ := u.(*Chan); t != nil {
|
||||
if sValue != nil {
|
||||
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
|
||||
}
|
||||
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)
|
||||
@ -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
|
||||
// (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
|
||||
|
||||
if rclause.Def {
|
||||
// short variable declaration; variable scope starts after the range clause
|
||||
// (the for loop opens a new scope, so variables on the lhs never redeclare
|
||||
// previously declared variables)
|
||||
// short variable declaration
|
||||
var vars []*Var
|
||||
for i, lhs := range lhs {
|
||||
if lhs == nil {
|
||||
@ -913,12 +915,8 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
|
||||
|
||||
// declare variables
|
||||
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 {
|
||||
// spec: "The scope of a constant or variable identifier declared inside
|
||||
// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
|
||||
// for short variable declarations) and ends at the end of the innermost
|
||||
// containing block."
|
||||
check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
|
||||
}
|
||||
} else {
|
||||
|
@ -21,6 +21,17 @@ func makeSubstMap(tpars []*TypeParam, targs []Type) substMap {
|
||||
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 {
|
||||
return len(m) == 0
|
||||
}
|
||||
@ -149,7 +160,10 @@ func (subst *subster) typ(typ Type) Type {
|
||||
methods, mcopied := subst.funcList(t.methods)
|
||||
embeddeds, ecopied := subst.typeList(t.embeddeds)
|
||||
if mcopied || ecopied {
|
||||
iface := &Interface{embeddeds: embeddeds, implicit: t.implicit, complete: t.complete}
|
||||
iface := subst.check.newInterface()
|
||||
iface.embeddeds = embeddeds
|
||||
iface.implicit = t.implicit
|
||||
iface.complete = t.complete
|
||||
// If we've changed the interface type, we may need to replace its
|
||||
// receiver if the receiver type is the original interface. Receivers of
|
||||
// *Named type are replaced during named type expansion.
|
||||
|
@ -92,15 +92,6 @@ func (xl termlist) norm() termlist {
|
||||
return rl
|
||||
}
|
||||
|
||||
// If the type set represented by xl is specified by a single (non-𝓤) term,
|
||||
// singleType returns that type. Otherwise it returns nil.
|
||||
func (xl termlist) singleType() Type {
|
||||
if nl := xl.norm(); len(nl) == 1 {
|
||||
return nl[0].typ // if nl.isAll() then typ is nil, which is ok
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// union returns the union xl ∪ yl.
|
||||
func (xl termlist) union(yl termlist) termlist {
|
||||
return append(xl, yl...).norm()
|
||||
|
@ -106,35 +106,6 @@ func TestTermlistNorm(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTermlistSingleType(t *testing.T) {
|
||||
// helper to deal with nil types
|
||||
tstring := func(typ Type) string {
|
||||
if typ == nil {
|
||||
return "nil"
|
||||
}
|
||||
return typ.String()
|
||||
}
|
||||
|
||||
for test, want := range map[string]string{
|
||||
"∅": "nil",
|
||||
"𝓤": "nil",
|
||||
"int": "int",
|
||||
"myInt": "myInt",
|
||||
"~int": "int",
|
||||
"~int ∪ string": "nil",
|
||||
"~int ∪ myInt": "int",
|
||||
"∅ ∪ int": "int",
|
||||
"∅ ∪ ~int": "int",
|
||||
"∅ ∪ ~int ∪ string": "nil",
|
||||
} {
|
||||
xl := maketl(test)
|
||||
got := tstring(xl.singleType())
|
||||
if got != want {
|
||||
t.Errorf("(%v).singleType() == %v; want %v", test, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTermlistUnion(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
xl, yl, want string
|
||||
|
@ -148,7 +148,7 @@ func _[
|
||||
_ = make /* ERROR expects 2 or 3 arguments */ (S1)
|
||||
_ = make(S1, 10, 20)
|
||||
_ = 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
|
||||
_ = make(map[string]int)
|
||||
@ -156,7 +156,7 @@ func _[
|
||||
_ = make(M1)
|
||||
_ = make(M1, 10)
|
||||
_ = 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
|
||||
_ = make(chan int)
|
||||
@ -164,7 +164,7 @@ func _[
|
||||
_ = make(C1)
|
||||
_ = make(C1, 10)
|
||||
_ = 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)
|
||||
}
|
||||
|
||||
|
@ -15,9 +15,9 @@ func append1() {
|
||||
var x int
|
||||
var s []byte
|
||||
_ = append() // ERROR not enough arguments
|
||||
_ = append("foo" /* ERROR not a slice */ )
|
||||
_ = append(nil /* ERROR not a slice */ , s)
|
||||
_ = append(x /* ERROR not a slice */ , s)
|
||||
_ = append("foo" /* ERROR must be a slice */ )
|
||||
_ = append(nil /* ERROR must be a slice */ , s)
|
||||
_ = append(x /* ERROR must be a slice */ , s)
|
||||
_ = append(s)
|
||||
_ = append(s, nil...)
|
||||
append /* ERROR not used */ (s)
|
||||
@ -77,7 +77,7 @@ func append3() {
|
||||
_ = append(f2())
|
||||
_ = append(f3())
|
||||
_ = 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() {
|
||||
|
@ -8,21 +8,21 @@ import "strconv"
|
||||
|
||||
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 _() {
|
||||
f := f0[string]
|
||||
f("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 _() {
|
||||
f := f1[int]
|
||||
f(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 _() {
|
||||
f := f2[byte]
|
||||
f(byte(0), []byte{})
|
||||
@ -38,7 +38,7 @@ func _() {
|
||||
// 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 _() {
|
||||
f := f4[int]
|
||||
var x int
|
||||
@ -46,7 +46,7 @@ func _() {
|
||||
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 _() {
|
||||
x := f5(1.2)
|
||||
var _ float64 = x.b
|
||||
@ -79,14 +79,14 @@ var _ = Double(MySlice{1})
|
||||
|
||||
type Setter[B any] interface {
|
||||
Set(string)
|
||||
~*B
|
||||
*B
|
||||
}
|
||||
|
||||
func FromStrings[T interface{}, PT Setter[T]](s []string) []T {
|
||||
result := make([]T, len(s))
|
||||
for i, v := range s {
|
||||
// The type of &result[i] is *T which is in the type list
|
||||
// of Setter2, so we can convert it to PT.
|
||||
// of Setter, so we can convert it to PT.
|
||||
p := PT(&result[i])
|
||||
// PT has a Set method.
|
||||
p.Set(v)
|
||||
|
@ -4,44 +4,46 @@
|
||||
|
||||
package typeInference
|
||||
|
||||
// As of issue #51527, type-type inference has been disabled.
|
||||
|
||||
// basic inference
|
||||
type Tb[P ~*Q, Q any] int
|
||||
func _() {
|
||||
var x Tb[*int]
|
||||
var x Tb /* ERROR got 1 arguments */ [*int]
|
||||
var y Tb[*int, int]
|
||||
x = y
|
||||
x = y /* ERROR cannot use y .* in assignment */
|
||||
_ = x
|
||||
}
|
||||
|
||||
// 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 _() {
|
||||
var x Tr[string]
|
||||
var x Tr /* ERROR got 1 arguments */ [string]
|
||||
var y Tr[string, ***string, **string, *string]
|
||||
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
|
||||
}
|
||||
|
||||
// other patterns of inference
|
||||
type To0[A any, B ~[]A] int
|
||||
type To1[A any, B ~struct{a A}] int
|
||||
type To2[A any, B ~[][]A] int
|
||||
type To3[A any, B ~[3]*A] int
|
||||
type To4[A any, B any, C ~struct{a A; b B}] int
|
||||
type To0[A any, B []A] int
|
||||
type To1[A any, B struct{a A}] int
|
||||
type To2[A any, B [][]A] int
|
||||
type To3[A any, B [3]*A] int
|
||||
type To4[A any, B any, C struct{a A; b B}] int
|
||||
func _() {
|
||||
var _ To0[int]
|
||||
var _ To1[int]
|
||||
var _ To2[int]
|
||||
var _ To3[int]
|
||||
var _ To4[int, string]
|
||||
var _ To0 /* ERROR got 1 arguments */ [int]
|
||||
var _ To1 /* ERROR got 1 arguments */ [int]
|
||||
var _ To2 /* ERROR got 1 arguments */ [int]
|
||||
var _ To3 /* ERROR got 1 arguments */ [int]
|
||||
var _ To4 /* ERROR got 2 arguments */ [int, string]
|
||||
}
|
||||
|
||||
// failed inference
|
||||
type Tf0[A, B any] int
|
||||
type Tf1[A any, B ~struct{a A; c C}, C any] int
|
||||
func _() {
|
||||
var _ Tf0 /* ERROR cannot infer B */ /* 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 _ Tf0 /* ERROR got 1 arguments but 2 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 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 | []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: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
|
||||
|
||||
@ -230,7 +230,7 @@ func _[
|
||||
for _, _ = range s1 {}
|
||||
|
||||
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
|
||||
for range a0 {}
|
||||
@ -243,7 +243,7 @@ func _[
|
||||
for _, _ = range a1 {}
|
||||
|
||||
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
|
||||
for range p0 {}
|
||||
@ -256,7 +256,7 @@ func _[
|
||||
for _, _ = range p1 {}
|
||||
|
||||
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
|
||||
for range m0 {}
|
||||
@ -269,7 +269,7 @@ func _[
|
||||
for _, _ = range m1 {}
|
||||
|
||||
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
|
||||
|
@ -78,7 +78,7 @@ func _() {
|
||||
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 _() {
|
||||
// related2 can be called with explicit instantiation.
|
||||
@ -109,16 +109,8 @@ func _() {
|
||||
related3[int, []int]()
|
||||
related3[byte, List[byte]]()
|
||||
|
||||
// Alternatively, the 2nd type argument can be inferred
|
||||
// from the first one through constraint type inference.
|
||||
related3[int]()
|
||||
|
||||
// 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]]()
|
||||
// The 2nd type argument cannot be inferred from the first
|
||||
// one because there's two possible choices: []Elem and
|
||||
// List[Elem].
|
||||
related3[int]( /* ERROR cannot infer Slice */ )
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ func (t T1[[ /* ERROR must be an identifier */ ]int]) m2() {}
|
||||
// style. In m3 below, int is the name of the local receiver type parameter
|
||||
// and it shadows the predeclared identifier int which then cannot be used
|
||||
// anymore as expected.
|
||||
// This is no different from locally redelaring a predeclared identifier
|
||||
// This is no different from locally re-declaring a predeclared identifier
|
||||
// and usually should be avoided. There are some notable exceptions; e.g.,
|
||||
// sometimes it makes sense to use the identifier "copy" which happens to
|
||||
// also be the name of a predeclared built-in function.
|
||||
|
@ -292,7 +292,7 @@ func _[T interface{~int|~float64}]() {
|
||||
|
||||
// It is possible to create composite literals of type parameter
|
||||
// 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 {
|
||||
return P{}
|
||||
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
|
||||
// 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
|
||||
|
||||
func _[P MyInts]() P {
|
||||
|
@ -35,7 +35,7 @@ func _() int {
|
||||
return deref(p)
|
||||
}
|
||||
|
||||
func addrOfCopy[V any, P ~*V](v V) P {
|
||||
func addrOfCopy[V any, P *V](v V) P {
|
||||
return &v
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ type _ struct{
|
||||
}
|
||||
|
||||
type _ struct{
|
||||
I3 // ERROR interface is .* comparable
|
||||
I3 // ERROR interface contains type constraints
|
||||
}
|
||||
|
||||
// General composite types.
|
||||
@ -59,19 +59,19 @@ type (
|
||||
_ []I1 // ERROR interface is .* comparable
|
||||
_ []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
|
||||
_ chan I3 // ERROR interface is .* comparable
|
||||
_ chan I3 // ERROR interface contains type constraints
|
||||
_ func(I1 /* ERROR interface is .* comparable */ )
|
||||
_ func() I2 // ERROR interface contains type constraints
|
||||
)
|
||||
|
||||
// Other cases.
|
||||
|
||||
var _ = [...]I3 /* ERROR interface is .* comparable */ {}
|
||||
var _ = [...]I3 /* ERROR interface contains type constraints */ {}
|
||||
|
||||
func _(x interface{}) {
|
||||
_ = x.(I3 /* ERROR interface is .* comparable */ )
|
||||
_ = x.(I3 /* ERROR interface contains type constraints */ )
|
||||
}
|
||||
|
||||
type T1[_ any] struct{}
|
||||
|
@ -9,7 +9,7 @@ const L = 10
|
||||
type (
|
||||
_ [L]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{}
|
||||
|
||||
B int
|
||||
|
@ -12,7 +12,7 @@ type C4 interface{ chan int | chan<- int }
|
||||
type C5[T any] interface{ ~chan T | <-chan 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) {
|
||||
@ -28,7 +28,7 @@ func _[T C2](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) {
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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 _() {
|
||||
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 }
|
||||
|
||||
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) {
|
||||
@ -28,7 +28,7 @@ func _[T C2](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) {
|
||||
|
@ -8,13 +8,13 @@
|
||||
|
||||
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
|
||||
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])
|
||||
_ = 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
|
||||
// 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
|
||||
|
||||
func f[P any](a, _ P) {
|
||||
var x int
|
||||
// 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 */)
|
||||
}
|
||||
|
||||
func g[P any](a, b P) {
|
||||
g(a, b)
|
||||
// TODO(gri) these error messages are incorrect because the code is valid
|
||||
g(&a, & /* ERROR type \*P of &b does not match inferred type \*P for P */ b)
|
||||
g([]P{}, [ /* ERROR type \[\]P of \[\]P{} does not match inferred type \[\]P for P */ ]P{})
|
||||
g(&a, &b)
|
||||
g([]P{}, []P{})
|
||||
|
||||
// work-around: provide type argument explicitly
|
||||
g[*P](&a, &b)
|
||||
|
@ -2,14 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// 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
|
||||
|
||||
func f[P *Q, Q any](P, Q) {
|
||||
// TODO(gri) these error messages are unclear
|
||||
_ = f[ /* ERROR P does not match \*Q */ P]
|
||||
_ = f[ /* ERROR cannot infer P */ *P]
|
||||
_ = f[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() {}
|
||||
|
||||
// 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
|
||||
s.f = 1
|
||||
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
|
||||
|
||||
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]) {
|
||||
|
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
|
||||
// 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
|
||||
|
||||
type Sf struct {
|
||||
@ -9,13 +13,13 @@ type Sf struct {
|
||||
}
|
||||
|
||||
func f0[P Sf](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
}
|
||||
|
||||
func f0t[P ~struct{f int}](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
}
|
||||
|
||||
var _ = f0[Sf]
|
||||
@ -25,8 +29,8 @@ var _ = f0[Sm /* ERROR does not implement */ ]
|
||||
var _ = f0t[Sm /* ERROR does not implement */ ]
|
||||
|
||||
func f1[P interface{ Sf; m() }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
p.m()
|
||||
}
|
||||
|
||||
@ -44,20 +48,20 @@ type Sfm struct {
|
||||
func (Sfm) m() {}
|
||||
|
||||
func f2[P interface{ Sfm; m() }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
p.m()
|
||||
}
|
||||
|
||||
var _ = f2[Sfm]
|
||||
|
||||
// special case: structural type is a named pointer type
|
||||
// special case: core type is a named pointer type
|
||||
|
||||
type PSfm *Sfm
|
||||
|
||||
func f3[P interface{ PSfm }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
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
|
||||
// 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
|
||||
|
||||
// The first example from the issue.
|
||||
@ -18,9 +22,12 @@ type numericAbs[T Numeric] interface {
|
||||
// AbsDifference computes the absolute value of the difference of
|
||||
// a and b, where the absolute value is determined by the Abs method.
|
||||
func absDifference[T numericAbs[T /* ERROR T does not implement Numeric */]](a, b T) T {
|
||||
// TODO: the error below should probably be positioned on the '-'.
|
||||
d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value
|
||||
return d.Abs()
|
||||
// Field accesses are not permitted for now. Keep an error so
|
||||
// we can find and fix this code once the situation changes.
|
||||
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.
|
||||
|
@ -16,7 +16,7 @@ func G[A, B any](F[A, B]) {
|
||||
|
||||
func _() {
|
||||
// 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 */)
|
||||
}
|
||||
|
||||
@ -46,9 +46,9 @@ func NSG[G any](c RSC[G]) {
|
||||
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
|
||||
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.
|
||||
// All types implement the Type interface.
|
||||
type Type interface {
|
||||
// Underlying returns the underlying type of a type
|
||||
// w/o following forwarding chains. Only used by
|
||||
// client packages.
|
||||
// Underlying returns the underlying type of a type.
|
||||
Underlying() Type
|
||||
|
||||
// String returns a string representation of a type.
|
||||
@ -27,13 +25,13 @@ func under(t Type) Type {
|
||||
return t.Underlying()
|
||||
}
|
||||
|
||||
// If t is not a type parameter, structuralType returns the underlying type.
|
||||
// If t is a type parameter, structuralType returns the single underlying
|
||||
// If t is not a type parameter, coreType returns the underlying type.
|
||||
// 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 set contains only unrestricted and restricted channel types (with
|
||||
// identical element types), the single underlying type is the restricted
|
||||
// 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)
|
||||
if tpar == nil {
|
||||
return under(t)
|
||||
@ -59,10 +57,10 @@ func structuralType(t Type) Type {
|
||||
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
|
||||
// a string, the result is of type (possibly untyped) string.
|
||||
func structuralString(t Type) Type {
|
||||
func coreString(t Type) Type {
|
||||
tpar, _ := t.(*TypeParam)
|
||||
if tpar == nil {
|
||||
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
|
||||
// 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 {
|
||||
return (*Checker)(nil).newTypeParam(obj, constraint)
|
||||
}
|
||||
|
||||
// check may be nil
|
||||
func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
|
||||
// Always increment lastID, even if it is not used.
|
||||
id := nextID()
|
||||
@ -50,9 +52,7 @@ func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
|
||||
// iface may mutate typ.bound, so we must ensure that iface() is called
|
||||
// at least once before the resulting TypeParam escapes.
|
||||
if check != nil {
|
||||
check.later(func() {
|
||||
typ.iface()
|
||||
})
|
||||
check.needsCleanup(typ)
|
||||
} else if constraint != nil {
|
||||
typ.iface()
|
||||
}
|
||||
@ -72,8 +72,10 @@ func (t *TypeParam) Constraint() Type {
|
||||
|
||||
// SetConstraint sets the type constraint for t.
|
||||
//
|
||||
// SetConstraint should not be called concurrently, but once SetConstraint
|
||||
// returns the receiver t is safe for concurrent use.
|
||||
// It must be called by users of NewTypeParam after the bound's underlying is
|
||||
// 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) {
|
||||
if bound == nil {
|
||||
panic("nil constraint")
|
||||
@ -93,9 +95,12 @@ func (t *TypeParam) String() string { return TypeString(t, nil) }
|
||||
// ----------------------------------------------------------------------------
|
||||
// Implementation
|
||||
|
||||
func (t *TypeParam) cleanup() {
|
||||
t.iface()
|
||||
t.check = nil
|
||||
}
|
||||
|
||||
// iface returns the constraint interface of t.
|
||||
// TODO(gri) If we make tparamIsIface the default, this should be renamed to under
|
||||
// (similar to Named.under).
|
||||
func (t *TypeParam) iface() *Interface {
|
||||
bound := t.bound
|
||||
|
||||
@ -136,16 +141,6 @@ func (t *TypeParam) iface() *Interface {
|
||||
return ityp
|
||||
}
|
||||
|
||||
// singleType returns the single type of the type parameter constraint; or nil.
|
||||
func (t *TypeParam) singleType() Type {
|
||||
return t.iface().typeSet().singleType()
|
||||
}
|
||||
|
||||
// hasTerms reports whether the type parameter constraint has specific type terms.
|
||||
func (t *TypeParam) hasTerms() bool {
|
||||
return t.iface().typeSet().hasTerms()
|
||||
}
|
||||
|
||||
// is calls f with the specific type terms of t's constraint and reports whether
|
||||
// all calls to f returned true. If there are no specific terms, is
|
||||
// returns the result of f(nil).
|
||||
|
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