mirror of https://github.com/golang/go.git
[release-branch.go1.18] all: merge master (acc5f55) into release-branch.go1.18
Merge List: + 2022-02-28acc5f55baccmd/go: make work and work_edit script tests version-independent + 2022-02-28f04d5c118ccmd/internal/obj/riscv/testdata/testbranch: add //go:build lines + 2022-02-289fe3676bc7all: fix typos + 2022-02-28f9285818b6go/types, types2: fix string to type parameter conversions + 2022-02-28eb8198d2f6cmd/compile: deal with constructed types that have shapes in them + 2022-02-28b33592dcfdspec: the -'s possessive suffix is English, not code + 2022-02-2857e3809884runtime: avoid cgo_unsafe_args for syscall.syscall functions on darwin/arm64 + 2022-02-2806a43e4ab6cmd/compile: fix case for structural types where we should be looking at typeparams + 2022-02-280907d57abfcmd/compile: emit types of constants which are instantiated generic types + 2022-02-289c4a8620c8CONTRIBUTORS: update for the Go 1.18 release + 2022-02-2857dda9795dtest: add new test case for 51219 that triggers the types2 issue + 2022-02-26a064a4f29acmd/compile: ensure dictionary assignment statements are defining statements + 2022-02-26286e3e61aago/types, types2: report an error for x.sel where x is a built-in + 2022-02-2501e522a973go/types,types2: revert documentation for Type.Underlying + 2022-02-2526999cfd84runtime/internal/atomic: set SP delta correctly for 64-bit atomic functions on ARM + 2022-02-257c694fbad1go/types, types2: delay receiver type validation + 2022-02-2555e5b03cb3doc/go1.18: note changes to automatic go.mod and go.sum updates + 2022-02-256d810241ebdoc/go1.18: document minimum Linux kernel version + 2022-02-25b8b3196375doc/go1.18: document method set limitation for method selectors + 2022-02-24c0840a7c72go/types, types2: method recv type parameter count must match base type parameter count + 2022-02-24c15527f0b0go/types, types2: implement adjCoreType using TypeParam.is + 2022-02-245a9fc946b4cmd/go: avoid +incompatible major versions if a go.mod file exists in a subdirectory for that version + 2022-02-244edefe9568cmd/compile: delay all call transforms if in a generic function + 2022-02-248c5904f149doc/go1.18: mention runtime/pprof improvements + 2022-02-24b2dfec100adoc/go1.18: fix typo in AMD64 port section + 2022-02-2478e99761fcgo/types, types2: don't crash if comp. literal element type has no core type + 2022-02-23e94f7df957go/types, types2: generalize cleanup phase after type checking + 2022-02-23163da6feb5go/types, types2: add "dynamic" flag to comparable predicate + 2022-02-23e534907f65go/types: delete unnecessary slice construction + 2022-02-23d0c3b01162doc/go1.18: drop misplaced period + 2022-02-2235170365c8net: document methods of Buffers + 2022-02-223140625606doc/go1.18: correct "go build -asan" HTML tag + 2022-02-22d17b65ff54crypto/x509, runtime: fix occasional spurious “certificate is expired” + 2022-02-21c9fe126c8bdoc/go1.18: fix a few small typos, add a few commas + 2022-02-20851ecea4ccencoding/xml: embedded reference to substruct causes XML marshaller to panic on encoding + 2022-02-190261fa616atestdata: fix typo in comment + 2022-02-19903e7cc699doc/go1.18: fix grammar error + 2022-02-19e002cf4df7strings: fix typo in comment + 2022-02-1861b5c866a9doc/go1.18: document Go 1.17 bootstrap and //go:build fix + 2022-02-18d27248c52fruntime: save some stack space for racecall on ARM64 + 2022-02-18d93cc8cb96runtime: define racefuncenter and racefuncexit as ABIInternal + 2022-02-1820b177268freflect: call ABIInternal moveMakeFuncArgPtrs on ARM64 + 2022-02-18d35ed09486cmd/compile: fix importers to deal with recursion through type constraints + 2022-02-16eaf040502bos: eliminate arbitrary sleep in Kill tests Change-Id: I74352b70d97c6fd4a45aee4e222160ea2a7854ae
This commit is contained in:
commit
9f2f0ee6ce
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>
|
||||
|
|
|
|||
130
doc/go1.18.html
130
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,12 +363,7 @@ 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, CL 344572 -->
|
||||
The <code>go</code> <code>mod</code> <code>tidy</code> command now retains
|
||||
|
|
@ -342,6 +375,8 @@ 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
|
||||
|
|
@ -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,11 +422,28 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
</ul>
|
||||
</p>
|
||||
|
||||
<h4 id="go-build-lines"><code>//go:build</code> lines</h4>
|
||||
|
||||
<p><!-- CL 240611 -->
|
||||
TODO: <a href="https://golang.org/cl/240611">https://golang.org/cl/240611</a>: 240611: cmd/fix: add buildtag fix
|
||||
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>
|
||||
|
||||
<h3 id="gofmt"><code>gofmt</code></h3>
|
||||
<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
|
||||
|
|
@ -388,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>
|
||||
|
||||
|
|
@ -476,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>
|
||||
|
||||
|
|
@ -506,14 +569,21 @@ 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="build">Build</h2>
|
||||
<h2 id="bootstrap">Bootstrap</h2>
|
||||
|
||||
<p><!-- CL 369914, CL 370274 -->
|
||||
TODO: <a href="https://golang.org/cl/369914">https://golang.org/cl/369914</a>: for default bootstrap, use Go 1.17 if present, falling back to Go 1.4
|
||||
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>
|
||||
|
|
@ -640,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>
|
||||
|
|
@ -1003,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>
|
||||
|
|
@ -1016,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>
|
||||
|
||||
|
|
@ -1101,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 -->
|
||||
|
|
@ -1170,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>
|
||||
|
|
@ -1179,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 -->
|
||||
|
|
@ -1251,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>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<!--{
|
||||
"Title": "The Go Programming Language Specification - Go 1.18 Draft",
|
||||
"Subtitle": "Version of Feb 14, 2022",
|
||||
"Subtitle": "Version of Feb 28, 2022",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
|
|
@ -2008,7 +2008,7 @@ by a value of type <code>T</code>.
|
|||
</ul>
|
||||
|
||||
<p>
|
||||
Additionally, if <code>x's</code> type <code>V</code> or <code>T</code> are type parameters
|
||||
Additionally, if <code>x</code>'s type <code>V</code> or <code>T</code> are type parameters
|
||||
with <a href="#Specific_types">specific types</a>, <code>x</code>
|
||||
is assignable to a variable of type <code>T</code> if one of the following conditions applies:
|
||||
</p>
|
||||
|
|
@ -7414,7 +7414,7 @@ an explicit call to <code>panic</code> or a <a href="#Run_time_panics">run-time
|
|||
terminates the execution of <code>F</code>.
|
||||
Any functions <a href="#Defer_statements">deferred</a> by <code>F</code>
|
||||
are then executed as usual.
|
||||
Next, any deferred functions run by <code>F's</code> caller are run,
|
||||
Next, any deferred functions run by <code>F</code>'s caller are run,
|
||||
and so on up to any deferred by the top-level function in the executing goroutine.
|
||||
At that point, the program is terminated and the error
|
||||
condition is reported, including the value of the argument to <code>panic</code>.
|
||||
|
|
|
|||
|
|
@ -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) &&
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
}
|
||||
// Shapes are grouped differently for structural types, so we
|
||||
// pass the type param to Shapify(), so we can distinguish.
|
||||
tparam = tparams[i]
|
||||
if !t.IsShape() {
|
||||
s1[i] = typecheck.Shapify(t, i, tparam)
|
||||
} else {
|
||||
|
|
@ -1055,8 +1059,6 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
|||
// Transform the conversion, now that we know the
|
||||
// type argument.
|
||||
m = transformConvCall(call)
|
||||
// CONVIFACE transformation was already done in noder2
|
||||
assert(m.Op() != ir.OCONVIFACE)
|
||||
|
||||
case ir.OMETHVALUE, ir.OMETHEXPR:
|
||||
// Redo the transformation of OXDOT, now that we
|
||||
|
|
@ -1076,14 +1078,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
|||
case ir.ONAME:
|
||||
name := call.X.Name()
|
||||
if name.BuiltinOp != ir.OXXX {
|
||||
switch name.BuiltinOp {
|
||||
case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
|
||||
// Transform these builtins now that we
|
||||
// know the type of the args.
|
||||
m = transformBuiltin(call)
|
||||
default:
|
||||
base.FatalfAt(call.Pos(), "Unexpected builtin op")
|
||||
}
|
||||
m = transformBuiltin(call)
|
||||
} else {
|
||||
// This is the case of a function value that was a
|
||||
// type parameter (implied to be a function via a
|
||||
|
|
@ -1154,6 +1149,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
|||
newfn.Dcl = append(newfn.Dcl, ldict)
|
||||
as := ir.NewAssignStmt(x.Pos(), ldict, cdict)
|
||||
as.SetTypecheck(1)
|
||||
ldict.Defn = as
|
||||
newfn.Body.Append(as)
|
||||
|
||||
// Create inst info for the instantiated closure. The dict
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -657,7 +657,7 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
|
|||
|
||||
// Compute tsym, the symbol that would normally be used as
|
||||
// the field name when embedding f.Type.
|
||||
// TODO(mdempsky): Check for other occurences of this logic
|
||||
// TODO(mdempsky): Check for other occurrences of this logic
|
||||
// and deduplicate.
|
||||
typ := f.Type
|
||||
if typ.IsPtr() {
|
||||
|
|
|
|||
|
|
@ -294,15 +294,14 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
|
|||
return "(" + strings.Join(res, ", ") + ")"
|
||||
}
|
||||
|
||||
func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) {
|
||||
measure := func(x int, unit string) string {
|
||||
s := fmt.Sprintf("%d %s", x, unit)
|
||||
if x != 1 {
|
||||
s += "s"
|
||||
}
|
||||
return s
|
||||
func measure(x int, unit string) string {
|
||||
if x != 1 {
|
||||
unit += "s"
|
||||
}
|
||||
return fmt.Sprintf("%d %s", x, unit)
|
||||
}
|
||||
|
||||
func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) {
|
||||
vars := measure(nvars, "variable")
|
||||
vals := measure(nvals, "value")
|
||||
rhs0 := rhs[0]
|
||||
|
|
|
|||
|
|
@ -525,7 +525,11 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
|
|||
}
|
||||
|
||||
check.exprOrType(x, e.X, false)
|
||||
if x.mode == invalid {
|
||||
switch x.mode {
|
||||
case builtin:
|
||||
check.errorf(e.Pos(), "cannot select on %s", x)
|
||||
goto Error
|
||||
case invalid:
|
||||
goto Error
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ type Checker struct {
|
|||
untyped map[syntax.Expr]exprInfo // map of expressions without final type
|
||||
delayed []action // stack of delayed action segments; segments are processed in FIFO order
|
||||
objPath []Object // path of object dependencies during type inference (for cycle reporting)
|
||||
defTypes []*Named // defined types created during type checking, for final validation.
|
||||
cleaners []cleaner // list of types that may need a final cleanup at the end of type-checking
|
||||
|
||||
// environment within which the current object is type-checked (valid only
|
||||
// for the duration of type-checking a specific object)
|
||||
|
|
@ -205,6 +205,16 @@ func (check *Checker) pop() Object {
|
|||
return obj
|
||||
}
|
||||
|
||||
type cleaner interface {
|
||||
cleanup()
|
||||
}
|
||||
|
||||
// needsCleanup records objects/types that implement the cleanup method
|
||||
// which will be called at the end of type-checking.
|
||||
func (check *Checker) needsCleanup(c cleaner) {
|
||||
check.cleaners = append(check.cleaners, c)
|
||||
}
|
||||
|
||||
// NewChecker returns a new Checker instance for a given package.
|
||||
// Package files may be added incrementally via checker.Files.
|
||||
func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
|
||||
|
|
@ -247,6 +257,8 @@ func (check *Checker) initFiles(files []*syntax.File) {
|
|||
check.methods = nil
|
||||
check.untyped = nil
|
||||
check.delayed = nil
|
||||
check.objPath = nil
|
||||
check.cleaners = nil
|
||||
|
||||
// determine package name and collect valid files
|
||||
pkg := check.pkg
|
||||
|
|
@ -315,8 +327,8 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
|
|||
print("== processDelayed ==")
|
||||
check.processDelayed(0) // incl. all functions
|
||||
|
||||
print("== expandDefTypes ==")
|
||||
check.expandDefTypes()
|
||||
print("== cleanup ==")
|
||||
check.cleanup()
|
||||
|
||||
print("== initOrder ==")
|
||||
check.initOrder()
|
||||
|
|
@ -344,7 +356,6 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
|
|||
check.recvTParamMap = nil
|
||||
check.brokenAliases = nil
|
||||
check.unionTypeSets = nil
|
||||
check.defTypes = nil
|
||||
check.ctxt = nil
|
||||
|
||||
// TODO(gri) There's more memory we should release at this point.
|
||||
|
|
@ -372,27 +383,13 @@ func (check *Checker) processDelayed(top int) {
|
|||
check.delayed = check.delayed[:top]
|
||||
}
|
||||
|
||||
func (check *Checker) expandDefTypes() {
|
||||
// Ensure that every defined type created in the course of type-checking has
|
||||
// either non-*Named underlying, or is unresolved.
|
||||
//
|
||||
// This guarantees that we don't leak any types whose underlying is *Named,
|
||||
// because any unresolved instances will lazily compute their underlying by
|
||||
// substituting in the underlying of their origin. The origin must have
|
||||
// either been imported or type-checked and expanded here, and in either case
|
||||
// its underlying will be fully expanded.
|
||||
for i := 0; i < len(check.defTypes); i++ {
|
||||
n := check.defTypes[i]
|
||||
switch n.underlying.(type) {
|
||||
case nil:
|
||||
if n.resolver == nil {
|
||||
panic("nil underlying")
|
||||
}
|
||||
case *Named:
|
||||
n.under() // n.under may add entries to check.defTypes
|
||||
}
|
||||
n.check = nil
|
||||
// cleanup runs cleanup for all collected cleaners.
|
||||
func (check *Checker) cleanup() {
|
||||
// Don't use a range clause since Named.cleanup may add more cleaners.
|
||||
for i := 0; i < len(check.cleaners); i++ {
|
||||
check.cleaners[i].cleanup()
|
||||
}
|
||||
check.cleaners = nil
|
||||
}
|
||||
|
||||
func (check *Checker) record(x *operand) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -899,7 +899,7 @@ func (check *Checker) incomparableCause(typ Type) string {
|
|||
}
|
||||
// see if we can extract a more specific error
|
||||
var cause string
|
||||
comparable(typ, nil, func(format string, args ...interface{}) {
|
||||
comparable(typ, true, nil, func(format string, args ...interface{}) {
|
||||
cause = check.sprintf(format, args...)
|
||||
})
|
||||
return cause
|
||||
|
|
@ -1360,6 +1360,10 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
|||
// no composite literal type present - use hint (element type of enclosing type)
|
||||
typ = hint
|
||||
base, _ = deref(coreType(typ)) // *T implies &T{}
|
||||
if base == nil {
|
||||
check.errorf(e, "invalid composite literal element type %s: no core type", typ)
|
||||
goto Error
|
||||
}
|
||||
|
||||
default:
|
||||
// TODO(gri) provide better error messages depending on context
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -591,15 +591,24 @@ func (check *Checker) inferB(pos syntax.Pos, tparams []*TypeParam, targs []Type)
|
|||
return
|
||||
}
|
||||
|
||||
// adjCoreType returns the core type of tpar unless the
|
||||
// type parameter embeds a single, possibly named type,
|
||||
// in which case it returns that single type instead.
|
||||
// (The core type is always the underlying type of that
|
||||
// single type.)
|
||||
func adjCoreType(tpar *TypeParam) Type {
|
||||
// If the type parameter embeds a single, possibly named
|
||||
// type, use that one instead of the core type (which is
|
||||
// always the underlying type of that single type).
|
||||
if single := tpar.singleType(); single != nil {
|
||||
if debug {
|
||||
assert(under(single) == coreType(tpar))
|
||||
var single *term
|
||||
if tpar.is(func(t *term) bool {
|
||||
if single == nil && t != nil {
|
||||
single = t
|
||||
return true
|
||||
}
|
||||
return single
|
||||
return false // zero or more than one terms
|
||||
}) {
|
||||
if debug {
|
||||
assert(under(single.typ) == coreType(tpar))
|
||||
}
|
||||
return single.typ
|
||||
}
|
||||
return coreType(tpar)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,11 +72,31 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar
|
|||
}
|
||||
// Ensure that typ is always expanded and sanity-checked.
|
||||
if check != nil {
|
||||
check.defTypes = append(check.defTypes, typ)
|
||||
check.needsCleanup(typ)
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
func (t *Named) cleanup() {
|
||||
// Ensure that every defined type created in the course of type-checking has
|
||||
// either non-*Named underlying, or is unresolved.
|
||||
//
|
||||
// This guarantees that we don't leak any types whose underlying is *Named,
|
||||
// because any unresolved instances will lazily compute their underlying by
|
||||
// substituting in the underlying of their origin. The origin must have
|
||||
// either been imported or type-checked and expanded here, and in either case
|
||||
// its underlying will be fully expanded.
|
||||
switch t.underlying.(type) {
|
||||
case nil:
|
||||
if t.resolver == nil {
|
||||
panic("nil underlying")
|
||||
}
|
||||
case *Named:
|
||||
t.under() // t.under may add entries to check.cleaners
|
||||
}
|
||||
t.check = nil
|
||||
}
|
||||
|
||||
// Obj returns the type name for the declaration defining the named type t. For
|
||||
// instantiated types, this is the type name of the base type.
|
||||
func (t *Named) Obj() *TypeName { return t.orig.obj } // for non-instances this is the same as t.obj
|
||||
|
|
@ -360,11 +380,11 @@ func expandNamed(ctxt *Context, n *Named, instPos syntax.Pos) (tparams *TypePara
|
|||
// that it wasn't substituted. In this case we need to create a new
|
||||
// *Interface before modifying receivers.
|
||||
if iface == n.orig.underlying {
|
||||
iface = &Interface{
|
||||
embeddeds: iface.embeddeds,
|
||||
complete: iface.complete,
|
||||
implicit: iface.implicit, // should be false but be conservative
|
||||
}
|
||||
old := iface
|
||||
iface = check.newInterface()
|
||||
iface.embeddeds = old.embeddeds
|
||||
iface.complete = old.complete
|
||||
iface.implicit = old.implicit // should be false but be conservative
|
||||
underlying = iface
|
||||
}
|
||||
iface.methods = methods
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,11 +116,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
|||
// lookup in the scope.
|
||||
for i, p := range rparams {
|
||||
if p.Value == "_" {
|
||||
tpar := sig.rparams.At(i)
|
||||
if check.recvTParamMap == nil {
|
||||
check.recvTParamMap = make(map[*syntax.Name]*TypeParam)
|
||||
}
|
||||
check.recvTParamMap[p] = tpar
|
||||
check.recvTParamMap[p] = tparams[i]
|
||||
}
|
||||
}
|
||||
// determine receiver type to get its type parameters
|
||||
|
|
@ -136,22 +135,23 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
|||
}
|
||||
}
|
||||
// provide type parameter bounds
|
||||
// - only do this if we have the right number (otherwise an error is reported elsewhere)
|
||||
if sig.RecvTypeParams().Len() == len(recvTParams) {
|
||||
// We have a list of *TypeNames but we need a list of Types.
|
||||
list := make([]Type, sig.RecvTypeParams().Len())
|
||||
for i, t := range sig.RecvTypeParams().list() {
|
||||
list[i] = t
|
||||
check.mono.recordCanon(t, recvTParams[i])
|
||||
}
|
||||
smap := makeSubstMap(recvTParams, list)
|
||||
for i, tpar := range sig.RecvTypeParams().list() {
|
||||
bound := recvTParams[i].bound
|
||||
// bound is (possibly) parameterized in the context of the
|
||||
// receiver type declaration. Substitute parameters for the
|
||||
// current context.
|
||||
tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil)
|
||||
if len(tparams) == len(recvTParams) {
|
||||
smap := makeRenameMap(recvTParams, tparams)
|
||||
for i, tpar := range tparams {
|
||||
recvTPar := recvTParams[i]
|
||||
check.mono.recordCanon(tpar, recvTPar)
|
||||
// recvTPar.bound is (possibly) parameterized in the context of the
|
||||
// receiver type declaration. Substitute parameters for the current
|
||||
// context.
|
||||
tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil)
|
||||
}
|
||||
} else if len(tparams) < len(recvTParams) {
|
||||
// Reporting an error here is a stop-gap measure to avoid crashes in the
|
||||
// compiler when a type parameter/argument cannot be inferred later. It
|
||||
// may lead to follow-on errors (see issues #51339, #51343).
|
||||
// TODO(gri) find a better solution
|
||||
got := measure(len(tparams), "type parameter")
|
||||
check.errorf(recvPar, "got %s, but receiver base type declares %d", got, len(recvTParams))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -194,66 +194,69 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
|||
case 1:
|
||||
recv = recvList[0]
|
||||
}
|
||||
sig.recv = recv
|
||||
|
||||
// TODO(gri) We should delay rtyp expansion to when we actually need the
|
||||
// receiver; thus all checks here should be delayed to later.
|
||||
rtyp, _ := deref(recv.typ)
|
||||
// Delay validation of receiver type as it may cause premature expansion
|
||||
// of types the receiver type is dependent on (see issues #51232, #51233).
|
||||
check.later(func() {
|
||||
rtyp, _ := deref(recv.typ)
|
||||
|
||||
// spec: "The receiver type must be of the form T or *T where T is a type name."
|
||||
// (ignore invalid types - error was reported before)
|
||||
if rtyp != Typ[Invalid] {
|
||||
var err string
|
||||
switch T := rtyp.(type) {
|
||||
case *Named:
|
||||
T.resolve(check.bestContext(nil))
|
||||
// The receiver type may be an instantiated type referred to
|
||||
// by an alias (which cannot have receiver parameters for now).
|
||||
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
|
||||
check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
|
||||
break
|
||||
}
|
||||
// spec: "The type denoted by T is called the receiver base type; it must not
|
||||
// be a pointer or interface type and it must be declared in the same package
|
||||
// as the method."
|
||||
if T.obj.pkg != check.pkg {
|
||||
err = "type not defined in this package"
|
||||
// spec: "The receiver type must be of the form T or *T where T is a type name."
|
||||
// (ignore invalid types - error was reported before)
|
||||
if rtyp != Typ[Invalid] {
|
||||
var err string
|
||||
switch T := rtyp.(type) {
|
||||
case *Named:
|
||||
T.resolve(check.bestContext(nil))
|
||||
// The receiver type may be an instantiated type referred to
|
||||
// by an alias (which cannot have receiver parameters for now).
|
||||
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
|
||||
check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ)
|
||||
break
|
||||
}
|
||||
// spec: "The type denoted by T is called the receiver base type; it must not
|
||||
// be a pointer or interface type and it must be declared in the same package
|
||||
// as the method."
|
||||
if T.obj.pkg != check.pkg {
|
||||
err = "type not defined in this package"
|
||||
if check.conf.CompilerErrorMessages {
|
||||
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
|
||||
err = ""
|
||||
}
|
||||
} else {
|
||||
// The underlying type of a receiver base type can be a type parameter;
|
||||
// e.g. for methods with a generic receiver T[P] with type T[P any] P.
|
||||
// TODO(gri) Such declarations are currently disallowed.
|
||||
// Revisit the need for underIs.
|
||||
underIs(T, func(u Type) bool {
|
||||
switch u := u.(type) {
|
||||
case *Basic:
|
||||
// unsafe.Pointer is treated like a regular pointer
|
||||
if u.kind == UnsafePointer {
|
||||
err = "unsafe.Pointer"
|
||||
return false
|
||||
}
|
||||
case *Pointer, *Interface:
|
||||
err = "pointer or interface type"
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
case *Basic:
|
||||
err = "basic or unnamed type"
|
||||
if check.conf.CompilerErrorMessages {
|
||||
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
|
||||
err = ""
|
||||
}
|
||||
} else {
|
||||
// The underlying type of a receiver base type can be a type parameter;
|
||||
// e.g. for methods with a generic receiver T[P] with type T[P any] P.
|
||||
underIs(T, func(u Type) bool {
|
||||
switch u := u.(type) {
|
||||
case *Basic:
|
||||
// unsafe.Pointer is treated like a regular pointer
|
||||
if u.kind == UnsafePointer {
|
||||
err = "unsafe.Pointer"
|
||||
return false
|
||||
}
|
||||
case *Pointer, *Interface:
|
||||
err = "pointer or interface type"
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
default:
|
||||
check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
|
||||
}
|
||||
case *Basic:
|
||||
err = "basic or unnamed type"
|
||||
if check.conf.CompilerErrorMessages {
|
||||
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
|
||||
err = ""
|
||||
if err != "" {
|
||||
check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
|
||||
}
|
||||
default:
|
||||
check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
|
||||
}
|
||||
if err != "" {
|
||||
check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
|
||||
// ok to continue
|
||||
}
|
||||
}
|
||||
sig.recv = recv
|
||||
}).describef(recv, "validate receiver %s", recv)
|
||||
}
|
||||
|
||||
sig.params = NewTuple(params...)
|
||||
|
|
|
|||
|
|
@ -160,7 +160,10 @@ func (subst *subster) typ(typ Type) Type {
|
|||
methods, mcopied := subst.funcList(t.methods)
|
||||
embeddeds, ecopied := subst.typeList(t.embeddeds)
|
||||
if mcopied || ecopied {
|
||||
iface := &Interface{embeddeds: embeddeds, implicit: t.implicit, complete: t.complete}
|
||||
iface := subst.check.newInterface()
|
||||
iface.embeddeds = embeddeds
|
||||
iface.implicit = t.implicit
|
||||
iface.complete = t.complete
|
||||
// If we've changed the interface type, we may need to replace its
|
||||
// receiver if the receiver type is the original interface. Receivers of
|
||||
// *Named type are replaced during named type expansion.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type RC[RG any] interface {
|
||||
~[]RG
|
||||
}
|
||||
|
||||
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||
|
||||
type F[RCT RC[RG], RG any] interface {
|
||||
Fn() Fn[RCT]
|
||||
}
|
||||
|
||||
type concreteF[RCT RC[RG], RG any] struct {
|
||||
makeFn func() Fn[RCT]
|
||||
}
|
||||
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||
return c.makeFn()
|
||||
}
|
||||
|
||||
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
|
||||
return &concreteF[RCT]{
|
||||
makeFn: nil,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type RC[RG any] interface {
|
||||
~[]RG
|
||||
}
|
||||
|
||||
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||
|
||||
type FFn[RCT RC[RG], RG any] func() Fn[RCT]
|
||||
|
||||
type F[RCT RC[RG], RG any] interface {
|
||||
Fn() Fn[RCT]
|
||||
}
|
||||
|
||||
type concreteF[RCT RC[RG], RG any] struct {
|
||||
makeFn FFn[RCT]
|
||||
}
|
||||
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||
return c.makeFn()
|
||||
}
|
||||
|
|
@ -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},
|
||||
})
|
||||
}
|
||||
|
|
@ -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 */ }}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file is tested when running "go test -run Manual"
|
||||
// without source arguments. Use for one-off debugging.
|
||||
|
||||
package p
|
||||
|
||||
type T[P any, B *P] struct{}
|
||||
|
||||
func (T /* ERROR cannot use generic type */ ) m0() {}
|
||||
func (T /* ERROR got 1 type parameter, but receiver base type declares 2 */ [_]) m1() {}
|
||||
func (T[_, _]) m2() {}
|
||||
// TODO(gri) this error is unfortunate (issue #51343)
|
||||
func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {}
|
||||
|
|
@ -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 */
|
||||
}
|
||||
|
|
@ -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("")
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ func NewTypeParam(obj *TypeName, constraint Type) *TypeParam {
|
|||
return (*Checker)(nil).newTypeParam(obj, constraint)
|
||||
}
|
||||
|
||||
// check may be nil
|
||||
func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
|
||||
// Always increment lastID, even if it is not used.
|
||||
id := nextID()
|
||||
|
|
@ -50,9 +51,7 @@ func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
|
|||
// iface may mutate typ.bound, so we must ensure that iface() is called
|
||||
// at least once before the resulting TypeParam escapes.
|
||||
if check != nil {
|
||||
check.later(func() {
|
||||
typ.iface()
|
||||
})
|
||||
check.needsCleanup(typ)
|
||||
} else if constraint != nil {
|
||||
typ.iface()
|
||||
}
|
||||
|
|
@ -93,9 +92,12 @@ func (t *TypeParam) String() string { return TypeString(t, nil) }
|
|||
// ----------------------------------------------------------------------------
|
||||
// Implementation
|
||||
|
||||
func (t *TypeParam) cleanup() {
|
||||
t.iface()
|
||||
t.check = nil
|
||||
}
|
||||
|
||||
// iface returns the constraint interface of t.
|
||||
// TODO(gri) If we make tparamIsIface the default, this should be renamed to under
|
||||
// (similar to Named.under).
|
||||
func (t *TypeParam) iface() *Interface {
|
||||
bound := t.bound
|
||||
|
||||
|
|
@ -136,16 +138,6 @@ func (t *TypeParam) iface() *Interface {
|
|||
return ityp
|
||||
}
|
||||
|
||||
// singleType returns the single type of the type parameter constraint; or nil.
|
||||
func (t *TypeParam) singleType() Type {
|
||||
return t.iface().typeSet().singleType()
|
||||
}
|
||||
|
||||
// hasTerms reports whether the type parameter constraint has specific type terms.
|
||||
func (t *TypeParam) hasTerms() bool {
|
||||
return t.iface().typeSet().hasTerms()
|
||||
}
|
||||
|
||||
// is calls f with the specific type terms of t's constraint and reports whether
|
||||
// all calls to f returned true. If there are no specific terms, is
|
||||
// returns the result of f(nil).
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ func (s *_TypeSet) IsComparable(seen map[Type]bool) bool {
|
|||
return s.comparable
|
||||
}
|
||||
return s.is(func(t *term) bool {
|
||||
return t != nil && comparable(t.typ, seen, nil)
|
||||
return t != nil && comparable(t.typ, false, seen, nil)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -103,9 +103,6 @@ func (s *_TypeSet) String() string {
|
|||
// hasTerms reports whether the type set has specific type terms.
|
||||
func (s *_TypeSet) hasTerms() bool { return !s.terms.isEmpty() && !s.terms.isAll() }
|
||||
|
||||
// singleType returns the single type in s if there is exactly one; otherwise the result is nil.
|
||||
func (s *_TypeSet) singleType() Type { return s.terms.singleType() }
|
||||
|
||||
// subsetOf reports whether s1 ⊆ s2.
|
||||
func (s1 *_TypeSet) subsetOf(s2 *_TypeSet) bool { return s1.terms.subsetOf(s2.terms) }
|
||||
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
|
|||
return typ
|
||||
|
||||
case *syntax.InterfaceType:
|
||||
typ := new(Interface)
|
||||
typ := check.newInterface()
|
||||
def.setUnderlying(typ)
|
||||
if def != nil {
|
||||
typ.obj = def.obj
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ func (check *Checker) validType0(typ Type, env *tparamEnv, path []Object) typeIn
|
|||
// would have reported a type cycle and couldn't have been
|
||||
// imported in the first place.
|
||||
assert(t.obj.pkg == check.pkg)
|
||||
t.underlying = Typ[Invalid] // t is in the current package (no race possibilty)
|
||||
t.underlying = Typ[Invalid] // t is in the current package (no race possibility)
|
||||
// Find the starting point of the cycle and report it.
|
||||
for i, tn := range path {
|
||||
if tn == t.obj {
|
||||
|
|
|
|||
|
|
@ -305,17 +305,46 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
|
|||
//
|
||||
// (If the version is +incompatible, then the go.mod file must not exist:
|
||||
// +incompatible is not an ongoing opt-out from semantic import versioning.)
|
||||
var canUseIncompatible func() bool
|
||||
canUseIncompatible = func() bool {
|
||||
var ok bool
|
||||
if r.codeDir == "" && r.pathMajor == "" {
|
||||
incompatibleOk := map[string]bool{}
|
||||
canUseIncompatible := func(v string) bool {
|
||||
if r.codeDir != "" || r.pathMajor != "" {
|
||||
// A non-empty codeDir indicates a module within a subdirectory,
|
||||
// which necessarily has a go.mod file indicating the module boundary.
|
||||
// A non-empty pathMajor indicates a module path with a major-version
|
||||
// suffix, which must match.
|
||||
return false
|
||||
}
|
||||
|
||||
ok, seen := incompatibleOk[""]
|
||||
if !seen {
|
||||
_, errGoMod := r.code.ReadFile(info.Name, "go.mod", codehost.MaxGoMod)
|
||||
if errGoMod != nil {
|
||||
ok = true
|
||||
ok = (errGoMod != nil)
|
||||
incompatibleOk[""] = ok
|
||||
}
|
||||
if !ok {
|
||||
// A go.mod file exists at the repo root.
|
||||
return false
|
||||
}
|
||||
|
||||
// Per https://go.dev/issue/51324, previous versions of the 'go' command
|
||||
// didn't always check for go.mod files in subdirectories, so if the user
|
||||
// requests a +incompatible version explicitly, we should continue to allow
|
||||
// it. Otherwise, if vN/go.mod exists, expect that release tags for that
|
||||
// major version are intended for the vN module.
|
||||
if v != "" && !strings.HasSuffix(statVers, "+incompatible") {
|
||||
major := semver.Major(v)
|
||||
ok, seen = incompatibleOk[major]
|
||||
if !seen {
|
||||
_, errGoModSub := r.code.ReadFile(info.Name, path.Join(major, "go.mod"), codehost.MaxGoMod)
|
||||
ok = (errGoModSub != nil)
|
||||
incompatibleOk[major] = ok
|
||||
}
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
canUseIncompatible = func() bool { return ok }
|
||||
return ok
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// checkCanonical verifies that the canonical version v is compatible with the
|
||||
|
|
@ -367,7 +396,7 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
|
|||
base := strings.TrimSuffix(v, "+incompatible")
|
||||
var errIncompatible error
|
||||
if !module.MatchPathMajor(base, r.pathMajor) {
|
||||
if canUseIncompatible() {
|
||||
if canUseIncompatible(base) {
|
||||
v = base + "+incompatible"
|
||||
} else {
|
||||
if r.pathMajor != "" {
|
||||
|
|
@ -495,7 +524,7 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
|
|||
// Save the highest non-retracted canonical tag for the revision.
|
||||
// If we don't find a better match, we'll use it as the canonical version.
|
||||
if tagIsCanonical && semver.Compare(highestCanonical, v) < 0 && !isRetracted(v) {
|
||||
if module.MatchPathMajor(v, r.pathMajor) || canUseIncompatible() {
|
||||
if module.MatchPathMajor(v, r.pathMajor) || canUseIncompatible(v) {
|
||||
highestCanonical = v
|
||||
}
|
||||
}
|
||||
|
|
@ -513,12 +542,12 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
|
|||
// retracted versions.
|
||||
allowedMajor := func(major string) func(v string) bool {
|
||||
return func(v string) bool {
|
||||
return (major == "" || semver.Major(v) == major) && !isRetracted(v)
|
||||
return ((major == "" && canUseIncompatible(v)) || semver.Major(v) == major) && !isRetracted(v)
|
||||
}
|
||||
}
|
||||
if pseudoBase == "" {
|
||||
var tag string
|
||||
if r.pseudoMajor != "" || canUseIncompatible() {
|
||||
if r.pseudoMajor != "" || canUseIncompatible("") {
|
||||
tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor(r.pseudoMajor))
|
||||
} else {
|
||||
// Allow either v1 or v0, but not incompatible higher versions.
|
||||
|
|
|
|||
|
|
@ -458,6 +458,54 @@ var codeRepoTests = []codeRepoTest{
|
|||
rev: "v3.0.0-devel",
|
||||
err: `resolves to version v0.1.1-0.20220203155313-d59622f6e4d7 (v3.0.0-devel is not a tag)`,
|
||||
},
|
||||
|
||||
// If v2/go.mod exists, then we should prefer to match the "v2"
|
||||
// pseudo-versions to the nested module, and resolve the module in the parent
|
||||
// directory to only compatible versions.
|
||||
//
|
||||
// However (https://go.dev/issue/51324), previous versions of the 'go' command
|
||||
// didn't always do so, so if the user explicitly requests a +incompatible
|
||||
// version (as would be present in an existing go.mod file), we should
|
||||
// continue to allow it.
|
||||
{
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/v2sub.git",
|
||||
rev: "80beb17a1603",
|
||||
version: "v0.0.0-20220222205507-80beb17a1603",
|
||||
name: "80beb17a16036f17a5aedd1bb5bd6d407b3c6dc5",
|
||||
short: "80beb17a1603",
|
||||
time: time.Date(2022, 2, 22, 20, 55, 7, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/v2sub.git",
|
||||
rev: "v2.0.0",
|
||||
err: `module contains a go.mod file, so module path must match major version ("vcs-test.golang.org/git/v2sub.git/v2")`,
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/v2sub.git",
|
||||
rev: "v2.0.1-0.20220222205507-80beb17a1603",
|
||||
err: `module contains a go.mod file, so module path must match major version ("vcs-test.golang.org/git/v2sub.git/v2")`,
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/v2sub.git",
|
||||
rev: "v2.0.0+incompatible",
|
||||
version: "v2.0.0+incompatible",
|
||||
name: "5fcd3eaeeb391d399f562fd45a50dac9fc34ae8b",
|
||||
short: "5fcd3eaeeb39",
|
||||
time: time.Date(2022, 2, 22, 20, 53, 33, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
vcs: "git",
|
||||
path: "vcs-test.golang.org/git/v2sub.git",
|
||||
rev: "v2.0.1-0.20220222205507-80beb17a1603+incompatible",
|
||||
version: "v2.0.1-0.20220222205507-80beb17a1603+incompatible",
|
||||
name: "80beb17a16036f17a5aedd1bb5bd6d407b3c6dc5",
|
||||
short: "80beb17a1603",
|
||||
time: time.Date(2022, 2, 22, 20, 55, 7, 0, time.UTC),
|
||||
},
|
||||
}
|
||||
|
||||
func TestCodeRepo(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ go env GOWORK
|
|||
! stdout .
|
||||
|
||||
go work init ./a ./b
|
||||
cmp go.work go.work.want
|
||||
cmpenv go.work go.work.want
|
||||
go env GOWORK
|
||||
stdout '^'$WORK'(\\|/)gopath(\\|/)src(\\|/)go.work$'
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ use (
|
|||
../src/a
|
||||
)
|
||||
-- go.work.want --
|
||||
go 1.18
|
||||
go $goversion
|
||||
|
||||
use (
|
||||
./a
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
# Test editing go.work files.
|
||||
|
||||
go work init m
|
||||
cmp go.work go.work.want_initial
|
||||
cmpenv go.work go.work.want_initial
|
||||
|
||||
go work edit -use n
|
||||
cmp go.work go.work.want_use_n
|
||||
cmpenv go.work go.work.want_use_n
|
||||
|
||||
go work edit -go 1.18
|
||||
cmp go.work go.work.want_go_118
|
||||
|
|
@ -39,11 +39,11 @@ module m
|
|||
|
||||
go 1.18
|
||||
-- go.work.want_initial --
|
||||
go 1.18
|
||||
go $goversion
|
||||
|
||||
use ./m
|
||||
-- go.work.want_use_n --
|
||||
go 1.18
|
||||
go $goversion
|
||||
|
||||
use (
|
||||
./m
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build riscv64
|
||||
// +build riscv64
|
||||
|
||||
package testbranch
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build riscv64
|
||||
// +build riscv64
|
||||
|
||||
#include "textflag.h"
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ func CFStringToString(ref CFRef) string {
|
|||
// TimeToCFDateRef converts a time.Time into an apple CFDateRef
|
||||
func TimeToCFDateRef(t time.Time) CFRef {
|
||||
secs := t.Sub(time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)).Seconds()
|
||||
ref := CFDateCreate(int(secs))
|
||||
ref := CFDateCreate(secs)
|
||||
return ref
|
||||
}
|
||||
|
||||
|
|
@ -170,8 +170,8 @@ func x509_CFArrayAppendValue_trampoline()
|
|||
|
||||
//go:cgo_import_dynamic x509_CFDateCreate CFDateCreate "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
|
||||
|
||||
func CFDateCreate(seconds int) CFRef {
|
||||
ret := syscall(abi.FuncPCABI0(x509_CFDateCreate_trampoline), kCFAllocatorDefault, uintptr(seconds), 0, 0, 0, 0)
|
||||
func CFDateCreate(seconds float64) CFRef {
|
||||
ret := syscall(abi.FuncPCABI0(x509_CFDateCreate_trampoline), kCFAllocatorDefault, 0, 0, 0, 0, seconds)
|
||||
return CFRef(ret)
|
||||
}
|
||||
func x509_CFDateCreate_trampoline()
|
||||
|
|
@ -193,7 +193,7 @@ func CFStringCreateExternalRepresentation(strRef CFRef) CFRef {
|
|||
func x509_CFStringCreateExternalRepresentation_trampoline()
|
||||
|
||||
// syscall is implemented in the runtime package (runtime/sys_darwin.go)
|
||||
func syscall(fn, a1, a2, a3, a4, a5, a6 uintptr) uintptr
|
||||
func syscall(fn, a1, a2, a3, a4, a5 uintptr, f1 float64) uintptr
|
||||
|
||||
// ReleaseCFArray iterates through an array, releasing its contents, and then
|
||||
// releases the array itself. This is necessary because we cannot, easily, set the
|
||||
|
|
|
|||
|
|
@ -512,7 +512,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
|
|||
}
|
||||
fv := finfo.value(val, dontInitNilPointers)
|
||||
|
||||
if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) {
|
||||
if finfo.flags&fOmitEmpty != 0 && (!fv.IsValid() || isEmptyValue(fv)) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2495,3 +2495,39 @@ func TestInvalidXMLName(t *testing.T) {
|
|||
t.Errorf("error %q does not contain %q", err, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 50164. Crash on zero value XML attribute.
|
||||
type LayerOne struct {
|
||||
XMLName Name `xml:"l1"`
|
||||
|
||||
Value *float64 `xml:"value,omitempty"`
|
||||
*LayerTwo `xml:",omitempty"`
|
||||
}
|
||||
|
||||
type LayerTwo struct {
|
||||
ValueTwo *int `xml:"value_two,attr,omitempty"`
|
||||
}
|
||||
|
||||
func TestMarshalZeroValue(t *testing.T) {
|
||||
proofXml := `<l1><value>1.2345</value></l1>`
|
||||
var l1 LayerOne
|
||||
err := Unmarshal([]byte(proofXml), &l1)
|
||||
if err != nil {
|
||||
t.Fatalf("unmarshal XML error: %v", err)
|
||||
}
|
||||
want := float64(1.2345)
|
||||
got := *l1.Value
|
||||
if got != want {
|
||||
t.Fatalf("unexpected unmarshal result, want %f but got %f", want, got)
|
||||
}
|
||||
|
||||
// Marshal again (or Encode again)
|
||||
// In issue 50164, here `Marshal(l1)` will panic because of the zero value of xml attribute ValueTwo `value_two`.
|
||||
anotherXML, err := Marshal(l1)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal XML error: %v", err)
|
||||
}
|
||||
if string(anotherXML) != proofXml {
|
||||
t.Fatalf("unexpected unmarshal result, want %q but got %q", proofXml, anotherXML)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,6 +181,15 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, dataRea
|
|||
p.doDecl(localpkg, name)
|
||||
}
|
||||
|
||||
// SetConstraint can't be called if the constraint type is not yet complete.
|
||||
// When type params are created in the 'P' case of (*importReader).obj(),
|
||||
// the associated constraint type may not be complete due to recursion.
|
||||
// Therefore, we defer calling SetConstraint there, and call it here instead
|
||||
// after all types are complete.
|
||||
for _, d := range p.later {
|
||||
d.t.SetConstraint(d.constraint)
|
||||
}
|
||||
|
||||
for _, typ := range p.interfaceList {
|
||||
typ.Complete()
|
||||
}
|
||||
|
|
@ -195,6 +204,11 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, dataRea
|
|||
return localpkg, nil
|
||||
}
|
||||
|
||||
type setConstraintArgs struct {
|
||||
t *types.TypeParam
|
||||
constraint types.Type
|
||||
}
|
||||
|
||||
type iimporter struct {
|
||||
exportVersion int64
|
||||
ipath string
|
||||
|
|
@ -211,6 +225,9 @@ type iimporter struct {
|
|||
|
||||
fake fakeFileSet
|
||||
interfaceList []*types.Interface
|
||||
|
||||
// Arguments for calls to SetConstraint that are deferred due to recursive types
|
||||
later []setConstraintArgs
|
||||
}
|
||||
|
||||
func (p *iimporter) doDecl(pkg *types.Package, name string) {
|
||||
|
|
@ -391,7 +408,11 @@ func (r *importReader) obj(name string) {
|
|||
}
|
||||
iface.MarkImplicit()
|
||||
}
|
||||
t.SetConstraint(constraint)
|
||||
// The constraint type may not be complete, if we
|
||||
// are in the middle of a type recursion involving type
|
||||
// constraints. So, we defer SetConstraint until we have
|
||||
// completely set up all types in ImportData.
|
||||
r.p.later = append(r.p.later, setConstraintArgs{t: t, constraint: constraint})
|
||||
|
||||
case 'V':
|
||||
typ := r.typ()
|
||||
|
|
|
|||
|
|
@ -290,15 +290,14 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
|
|||
return "(" + strings.Join(res, ", ") + ")"
|
||||
}
|
||||
|
||||
func (check *Checker) assignError(rhs []ast.Expr, nvars, nvals int) {
|
||||
measure := func(x int, unit string) string {
|
||||
s := fmt.Sprintf("%d %s", x, unit)
|
||||
if x != 1 {
|
||||
s += "s"
|
||||
}
|
||||
return s
|
||||
func measure(x int, unit string) string {
|
||||
if x != 1 {
|
||||
unit += "s"
|
||||
}
|
||||
return fmt.Sprintf("%d %s", x, unit)
|
||||
}
|
||||
|
||||
func (check *Checker) assignError(rhs []ast.Expr, nvars, nvals int) {
|
||||
vars := measure(nvars, "variable")
|
||||
vals := measure(nvals, "value")
|
||||
rhs0 := rhs[0]
|
||||
|
|
|
|||
|
|
@ -527,7 +527,12 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
|||
}
|
||||
|
||||
check.exprOrType(x, e.X, false)
|
||||
if x.mode == invalid {
|
||||
switch x.mode {
|
||||
case builtin:
|
||||
// types2 uses the position of '.' for the error
|
||||
check.errorf(e.Sel, _UncalledBuiltin, "cannot select on %s", x)
|
||||
goto Error
|
||||
case invalid:
|
||||
goto Error
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ type Checker struct {
|
|||
untyped map[ast.Expr]exprInfo // map of expressions without final type
|
||||
delayed []action // stack of delayed action segments; segments are processed in FIFO order
|
||||
objPath []Object // path of object dependencies during type inference (for cycle reporting)
|
||||
defTypes []*Named // defined types created during type checking, for final validation.
|
||||
cleaners []cleaner // list of types that may need a final cleanup at the end of type-checking
|
||||
|
||||
// environment within which the current object is type-checked (valid only
|
||||
// for the duration of type-checking a specific object)
|
||||
|
|
@ -212,6 +212,16 @@ func (check *Checker) pop() Object {
|
|||
return obj
|
||||
}
|
||||
|
||||
type cleaner interface {
|
||||
cleanup()
|
||||
}
|
||||
|
||||
// needsCleanup records objects/types that implement the cleanup method
|
||||
// which will be called at the end of type-checking.
|
||||
func (check *Checker) needsCleanup(c cleaner) {
|
||||
check.cleaners = append(check.cleaners, c)
|
||||
}
|
||||
|
||||
// NewChecker returns a new Checker instance for a given package.
|
||||
// Package files may be added incrementally via checker.Files.
|
||||
func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker {
|
||||
|
|
@ -255,6 +265,8 @@ func (check *Checker) initFiles(files []*ast.File) {
|
|||
check.methods = nil
|
||||
check.untyped = nil
|
||||
check.delayed = nil
|
||||
check.objPath = nil
|
||||
check.cleaners = nil
|
||||
|
||||
// determine package name and collect valid files
|
||||
pkg := check.pkg
|
||||
|
|
@ -304,22 +316,37 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
|
|||
|
||||
defer check.handleBailout(&err)
|
||||
|
||||
print := func(msg string) {
|
||||
if trace {
|
||||
fmt.Println()
|
||||
fmt.Println(msg)
|
||||
}
|
||||
}
|
||||
|
||||
print("== initFiles ==")
|
||||
check.initFiles(files)
|
||||
|
||||
print("== collectObjects ==")
|
||||
check.collectObjects()
|
||||
|
||||
print("== packageObjects ==")
|
||||
check.packageObjects()
|
||||
|
||||
print("== processDelayed ==")
|
||||
check.processDelayed(0) // incl. all functions
|
||||
|
||||
check.expandDefTypes()
|
||||
print("== cleanup ==")
|
||||
check.cleanup()
|
||||
|
||||
print("== initOrder ==")
|
||||
check.initOrder()
|
||||
|
||||
if !check.conf.DisableUnusedImportCheck {
|
||||
print("== unusedImports ==")
|
||||
check.unusedImports()
|
||||
}
|
||||
|
||||
print("== recordUntyped ==")
|
||||
check.recordUntyped()
|
||||
|
||||
if check.firstErr == nil {
|
||||
|
|
@ -337,7 +364,6 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
|
|||
check.recvTParamMap = nil
|
||||
check.brokenAliases = nil
|
||||
check.unionTypeSets = nil
|
||||
check.defTypes = nil
|
||||
check.ctxt = nil
|
||||
|
||||
// TODO(rFindley) There's more memory we should release at this point.
|
||||
|
|
@ -365,27 +391,13 @@ func (check *Checker) processDelayed(top int) {
|
|||
check.delayed = check.delayed[:top]
|
||||
}
|
||||
|
||||
func (check *Checker) expandDefTypes() {
|
||||
// Ensure that every defined type created in the course of type-checking has
|
||||
// either non-*Named underlying, or is unresolved.
|
||||
//
|
||||
// This guarantees that we don't leak any types whose underlying is *Named,
|
||||
// because any unresolved instances will lazily compute their underlying by
|
||||
// substituting in the underlying of their origin. The origin must have
|
||||
// either been imported or type-checked and expanded here, and in either case
|
||||
// its underlying will be fully expanded.
|
||||
for i := 0; i < len(check.defTypes); i++ {
|
||||
n := check.defTypes[i]
|
||||
switch n.underlying.(type) {
|
||||
case nil:
|
||||
if n.resolver == nil {
|
||||
panic("nil underlying")
|
||||
}
|
||||
case *Named:
|
||||
n.under() // n.under may add entries to check.defTypes
|
||||
}
|
||||
n.check = nil
|
||||
// cleanup runs cleanup for all collected cleaners.
|
||||
func (check *Checker) cleanup() {
|
||||
// Don't use a range clause since Named.cleanup may add more cleaners.
|
||||
for i := 0; i < len(check.cleaners); i++ {
|
||||
check.cleaners[i].cleanup()
|
||||
}
|
||||
check.cleaners = nil
|
||||
}
|
||||
|
||||
func (check *Checker) record(x *operand) {
|
||||
|
|
|
|||
|
|
@ -48,11 +48,14 @@ func (check *Checker) conversion(x *operand, T Type) {
|
|||
// have specific types, constant x cannot be
|
||||
// converted.
|
||||
ok = T.(*TypeParam).underIs(func(u Type) bool {
|
||||
// t is nil if there are no specific type terms
|
||||
// u is nil if there are no specific type terms
|
||||
if u == nil {
|
||||
cause = check.sprintf("%s does not contain specific types", T)
|
||||
return false
|
||||
}
|
||||
if isString(x.typ) && isBytesOrRunes(u) {
|
||||
return true
|
||||
}
|
||||
if !constConvertibleTo(u, nil) {
|
||||
cause = check.sprintf("cannot convert %s to %s (in %s)", x, u, T)
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -624,7 +624,6 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list *ast.FieldList
|
|||
}()
|
||||
|
||||
index := 0
|
||||
var bounds []Type
|
||||
for _, f := range list.List {
|
||||
var bound Type
|
||||
// NOTE: we may be able to assert that f.Type != nil here, but this is not
|
||||
|
|
@ -642,7 +641,6 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list *ast.FieldList
|
|||
} else {
|
||||
bound = Typ[Invalid]
|
||||
}
|
||||
bounds = append(bounds, bound)
|
||||
for i := range f.Names {
|
||||
tparams[index+i].bound = bound
|
||||
}
|
||||
|
|
|
|||
|
|
@ -859,7 +859,7 @@ func (check *Checker) incomparableCause(typ Type) string {
|
|||
}
|
||||
// see if we can extract a more specific error
|
||||
var cause string
|
||||
comparable(typ, nil, func(format string, args ...interface{}) {
|
||||
comparable(typ, true, nil, func(format string, args ...interface{}) {
|
||||
cause = check.sprintf(format, args...)
|
||||
})
|
||||
return cause
|
||||
|
|
@ -1339,6 +1339,10 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||
// no composite literal type present - use hint (element type of enclosing type)
|
||||
typ = hint
|
||||
base, _ = deref(coreType(typ)) // *T implies &T{}
|
||||
if base == nil {
|
||||
check.errorf(e, _InvalidLit, "invalid composite literal element type %s: no core type", typ)
|
||||
goto Error
|
||||
}
|
||||
|
||||
default:
|
||||
// TODO(gri) provide better error messages depending on context
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst
|
|||
}
|
||||
|
||||
if !valid {
|
||||
// types2 uses the position of '[' for the error
|
||||
check.invalidOp(x, _NonIndexableOperand, "cannot index %s", x)
|
||||
x.mode = invalid
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -590,15 +590,24 @@ func (check *Checker) inferB(posn positioner, tparams []*TypeParam, targs []Type
|
|||
return
|
||||
}
|
||||
|
||||
// adjCoreType returns the core type of tpar unless the
|
||||
// type parameter embeds a single, possibly named type,
|
||||
// in which case it returns that single type instead.
|
||||
// (The core type is always the underlying type of that
|
||||
// single type.)
|
||||
func adjCoreType(tpar *TypeParam) Type {
|
||||
// If the type parameter embeds a single, possibly named
|
||||
// type, use that one instead of the core type (which is
|
||||
// always the underlying type of that single type).
|
||||
if single := tpar.singleType(); single != nil {
|
||||
if debug {
|
||||
assert(under(single) == coreType(tpar))
|
||||
var single *term
|
||||
if tpar.is(func(t *term) bool {
|
||||
if single == nil && t != nil {
|
||||
single = t
|
||||
return true
|
||||
}
|
||||
return single
|
||||
return false // zero or more than one terms
|
||||
}) {
|
||||
if debug {
|
||||
assert(under(single.typ) == coreType(tpar))
|
||||
}
|
||||
return single.typ
|
||||
}
|
||||
return coreType(tpar)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
|
|||
}
|
||||
|
||||
// set method receivers if necessary
|
||||
typ := new(Interface)
|
||||
typ := (*Checker)(nil).newInterface()
|
||||
for _, m := range methods {
|
||||
if sig := m.typ.(*Signature); sig.recv == nil {
|
||||
sig.recv = NewVar(m.pos, m.pkg, "", typ)
|
||||
|
|
@ -73,6 +73,15 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
|
|||
return typ
|
||||
}
|
||||
|
||||
// check may be nil
|
||||
func (check *Checker) newInterface() *Interface {
|
||||
typ := &Interface{check: check}
|
||||
if check != nil {
|
||||
check.needsCleanup(typ)
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// MarkImplicit marks the interface t as implicit, meaning this interface
|
||||
// corresponds to a constraint literal such as ~T or A|B without explicit
|
||||
// interface embedding. MarkImplicit should be called before any concurrent use
|
||||
|
|
@ -141,6 +150,11 @@ func (t *Interface) String() string { return TypeString(t, nil) }
|
|||
// ----------------------------------------------------------------------------
|
||||
// Implementation
|
||||
|
||||
func (t *Interface) cleanup() {
|
||||
t.check = nil
|
||||
t.embedPos = nil
|
||||
}
|
||||
|
||||
func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) {
|
||||
addEmbedded := func(pos token.Pos, typ Type) {
|
||||
ityp.embeddeds = append(ityp.embeddeds, typ)
|
||||
|
|
@ -210,16 +224,10 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
|
|||
sortMethods(ityp.methods)
|
||||
// (don't sort embeddeds: they must correspond to *embedPos entries)
|
||||
|
||||
// Compute type set with a non-nil *Checker as soon as possible
|
||||
// to report any errors. Subsequent uses of type sets will use
|
||||
// this computed type set and won't need to pass in a *Checker.
|
||||
//
|
||||
// Pin the checker to the interface type in the interim, in case the type set
|
||||
// must be used before delayed funcs are processed (see issue #48234).
|
||||
// TODO(rfindley): clean up use of *Checker with computeInterfaceTypeSet
|
||||
ityp.check = check
|
||||
// Compute type set as soon as possible to report any errors.
|
||||
// Subsequent uses of type sets will use this computed type
|
||||
// set and won't need to pass in a *Checker.
|
||||
check.later(func() {
|
||||
computeInterfaceTypeSet(check, iface.Pos(), ityp)
|
||||
ityp.check = nil
|
||||
}).describef(iface, "compute type set for %s", ityp)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,11 +72,31 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar
|
|||
}
|
||||
// Ensure that typ is always expanded and sanity-checked.
|
||||
if check != nil {
|
||||
check.defTypes = append(check.defTypes, typ)
|
||||
check.needsCleanup(typ)
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
func (t *Named) cleanup() {
|
||||
// Ensure that every defined type created in the course of type-checking has
|
||||
// either non-*Named underlying, or is unresolved.
|
||||
//
|
||||
// This guarantees that we don't leak any types whose underlying is *Named,
|
||||
// because any unresolved instances will lazily compute their underlying by
|
||||
// substituting in the underlying of their origin. The origin must have
|
||||
// either been imported or type-checked and expanded here, and in either case
|
||||
// its underlying will be fully expanded.
|
||||
switch t.underlying.(type) {
|
||||
case nil:
|
||||
if t.resolver == nil {
|
||||
panic("nil underlying")
|
||||
}
|
||||
case *Named:
|
||||
t.under() // t.under may add entries to check.cleaners
|
||||
}
|
||||
t.check = nil
|
||||
}
|
||||
|
||||
// Obj returns the type name for the declaration defining the named type t. For
|
||||
// instantiated types, this is the type name of the base type.
|
||||
func (t *Named) Obj() *TypeName {
|
||||
|
|
@ -362,11 +382,11 @@ func expandNamed(ctxt *Context, n *Named, instPos token.Pos) (tparams *TypeParam
|
|||
// that it wasn't substituted. In this case we need to create a new
|
||||
// *Interface before modifying receivers.
|
||||
if iface == n.orig.underlying {
|
||||
iface = &Interface{
|
||||
embeddeds: iface.embeddeds,
|
||||
complete: iface.complete,
|
||||
implicit: iface.implicit, // should be false but be conservative
|
||||
}
|
||||
old := iface
|
||||
iface = check.newInterface()
|
||||
iface.embeddeds = old.embeddeds
|
||||
iface.complete = old.complete
|
||||
iface.implicit = old.implicit // should be false but be conservative
|
||||
underlying = iface
|
||||
}
|
||||
iface.methods = methods
|
||||
|
|
|
|||
|
|
@ -104,11 +104,12 @@ func isGeneric(t Type) bool {
|
|||
|
||||
// Comparable reports whether values of type T are comparable.
|
||||
func Comparable(T Type) bool {
|
||||
return comparable(T, nil, nil)
|
||||
return comparable(T, true, nil, nil)
|
||||
}
|
||||
|
||||
// If dynamic is set, non-type parameter interfaces are always comparable.
|
||||
// If reportf != nil, it may be used to report why T is not comparable.
|
||||
func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})) bool {
|
||||
func comparable(T Type, dynamic bool, seen map[Type]bool, reportf func(string, ...interface{})) bool {
|
||||
if seen[T] {
|
||||
return true
|
||||
}
|
||||
|
|
@ -126,7 +127,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
|
|||
return true
|
||||
case *Struct:
|
||||
for _, f := range t.fields {
|
||||
if !comparable(f.typ, seen, nil) {
|
||||
if !comparable(f.typ, dynamic, seen, nil) {
|
||||
if reportf != nil {
|
||||
reportf("struct containing %s cannot be compared", f.typ)
|
||||
}
|
||||
|
|
@ -135,7 +136,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
|
|||
}
|
||||
return true
|
||||
case *Array:
|
||||
if !comparable(t.elem, seen, nil) {
|
||||
if !comparable(t.elem, dynamic, seen, nil) {
|
||||
if reportf != nil {
|
||||
reportf("%s cannot be compared", t)
|
||||
}
|
||||
|
|
@ -143,7 +144,7 @@ func comparable(T Type, seen map[Type]bool, reportf func(string, ...interface{})
|
|||
}
|
||||
return true
|
||||
case *Interface:
|
||||
return !isTypeParam(T) || t.typeSet().IsComparable(seen)
|
||||
return dynamic && !isTypeParam(T) || t.typeSet().IsComparable(seen)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,7 +112,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
|||
// - the receiver specification acts as local declaration for its type parameters, which may be blank
|
||||
_, rname, rparams := check.unpackRecv(recvPar.List[0].Type, true)
|
||||
if len(rparams) > 0 {
|
||||
sig.rparams = bindTParams(check.declareTypeParams(nil, rparams))
|
||||
tparams := check.declareTypeParams(nil, rparams)
|
||||
sig.rparams = bindTParams(tparams)
|
||||
// Blank identifiers don't get declared, so naive type-checking of the
|
||||
// receiver type expression would fail in Checker.collectParams below,
|
||||
// when Checker.ident cannot resolve the _ to a type.
|
||||
|
|
@ -122,11 +123,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
|||
// lookup in the scope.
|
||||
for i, p := range rparams {
|
||||
if p.Name == "_" {
|
||||
tpar := sig.rparams.At(i)
|
||||
if check.recvTParamMap == nil {
|
||||
check.recvTParamMap = make(map[*ast.Ident]*TypeParam)
|
||||
}
|
||||
check.recvTParamMap[p] = tpar
|
||||
check.recvTParamMap[p] = tparams[i]
|
||||
}
|
||||
}
|
||||
// determine receiver type to get its type parameters
|
||||
|
|
@ -142,22 +142,23 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
|||
}
|
||||
}
|
||||
// provide type parameter bounds
|
||||
// - only do this if we have the right number (otherwise an error is reported elsewhere)
|
||||
if sig.RecvTypeParams().Len() == len(recvTParams) {
|
||||
// We have a list of *TypeNames but we need a list of Types.
|
||||
list := make([]Type, sig.RecvTypeParams().Len())
|
||||
for i, t := range sig.RecvTypeParams().list() {
|
||||
list[i] = t
|
||||
check.mono.recordCanon(t, recvTParams[i])
|
||||
}
|
||||
smap := makeSubstMap(recvTParams, list)
|
||||
for i, tpar := range sig.RecvTypeParams().list() {
|
||||
bound := recvTParams[i].bound
|
||||
// bound is (possibly) parameterized in the context of the
|
||||
// receiver type declaration. Substitute parameters for the
|
||||
// current context.
|
||||
tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil)
|
||||
if len(tparams) == len(recvTParams) {
|
||||
smap := makeRenameMap(recvTParams, tparams)
|
||||
for i, tpar := range tparams {
|
||||
recvTPar := recvTParams[i]
|
||||
check.mono.recordCanon(tpar, recvTPar)
|
||||
// recvTPar.bound is (possibly) parameterized in the context of the
|
||||
// receiver type declaration. Substitute parameters for the current
|
||||
// context.
|
||||
tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil)
|
||||
}
|
||||
} else if len(tparams) < len(recvTParams) {
|
||||
// Reporting an error here is a stop-gap measure to avoid crashes in the
|
||||
// compiler when a type parameter/argument cannot be inferred later. It
|
||||
// may lead to follow-on errors (see issues #51339, #51343).
|
||||
// TODO(gri) find a better solution
|
||||
got := measure(len(tparams), "type parameter")
|
||||
check.errorf(recvPar, _BadRecv, "got %s, but receiver base type declares %d", got, len(recvTParams))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -192,66 +193,77 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
|||
switch len(recvList) {
|
||||
case 0:
|
||||
// error reported by resolver
|
||||
recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below
|
||||
recv = NewParam(token.NoPos, nil, "", Typ[Invalid]) // ignore recv below
|
||||
default:
|
||||
// more than one receiver
|
||||
check.error(recvList[len(recvList)-1], _BadRecv, "method must have exactly one receiver")
|
||||
check.error(recvList[len(recvList)-1], _InvalidRecv, "method must have exactly one receiver")
|
||||
fallthrough // continue with first receiver
|
||||
case 1:
|
||||
recv = recvList[0]
|
||||
}
|
||||
sig.recv = recv
|
||||
|
||||
// TODO(gri) We should delay rtyp expansion to when we actually need the
|
||||
// receiver; thus all checks here should be delayed to later.
|
||||
rtyp, _ := deref(recv.typ)
|
||||
// Delay validation of receiver type as it may cause premature expansion
|
||||
// of types the receiver type is dependent on (see issues #51232, #51233).
|
||||
check.later(func() {
|
||||
rtyp, _ := deref(recv.typ)
|
||||
|
||||
// spec: "The receiver type must be of the form T or *T where T is a type name."
|
||||
// (ignore invalid types - error was reported before)
|
||||
if rtyp != Typ[Invalid] {
|
||||
var err string
|
||||
switch T := rtyp.(type) {
|
||||
case *Named:
|
||||
T.resolve(check.bestContext(nil))
|
||||
// The receiver type may be an instantiated type referred to
|
||||
// by an alias (which cannot have receiver parameters for now).
|
||||
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
|
||||
check.errorf(atPos(recv.pos), _InvalidRecv, "cannot define methods on instantiated type %s", recv.typ)
|
||||
break
|
||||
}
|
||||
// spec: "The type denoted by T is called the receiver base type; it must not
|
||||
// be a pointer or interface type and it must be declared in the same package
|
||||
// as the method."
|
||||
if T.obj.pkg != check.pkg {
|
||||
err = "type not defined in this package"
|
||||
} else {
|
||||
// The underlying type of a receiver base type can be a type parameter;
|
||||
// e.g. for methods with a generic receiver T[P] with type T[P any] P.
|
||||
underIs(T, func(u Type) bool {
|
||||
switch u := u.(type) {
|
||||
case *Basic:
|
||||
// unsafe.Pointer is treated like a regular pointer
|
||||
if u.kind == UnsafePointer {
|
||||
err = "unsafe.Pointer"
|
||||
// spec: "The receiver type must be of the form T or *T where T is a type name."
|
||||
// (ignore invalid types - error was reported before)
|
||||
if rtyp != Typ[Invalid] {
|
||||
var err string
|
||||
switch T := rtyp.(type) {
|
||||
case *Named:
|
||||
T.resolve(check.bestContext(nil))
|
||||
// The receiver type may be an instantiated type referred to
|
||||
// by an alias (which cannot have receiver parameters for now).
|
||||
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
|
||||
check.errorf(recv, _InvalidRecv, "cannot define methods on instantiated type %s", recv.typ)
|
||||
break
|
||||
}
|
||||
// spec: "The type denoted by T is called the receiver base type; it must not
|
||||
// be a pointer or interface type and it must be declared in the same package
|
||||
// as the method."
|
||||
if T.obj.pkg != check.pkg {
|
||||
err = "type not defined in this package"
|
||||
if compilerErrorMessages {
|
||||
check.errorf(recv, _InvalidRecv, "cannot define new methods on non-local type %s", recv.typ)
|
||||
err = ""
|
||||
}
|
||||
} else {
|
||||
// The underlying type of a receiver base type can be a type parameter;
|
||||
// e.g. for methods with a generic receiver T[P] with type T[P any] P.
|
||||
// TODO(gri) Such declarations are currently disallowed.
|
||||
// Revisit the need for underIs.
|
||||
underIs(T, func(u Type) bool {
|
||||
switch u := u.(type) {
|
||||
case *Basic:
|
||||
// unsafe.Pointer is treated like a regular pointer
|
||||
if u.kind == UnsafePointer {
|
||||
err = "unsafe.Pointer"
|
||||
return false
|
||||
}
|
||||
case *Pointer, *Interface:
|
||||
err = "pointer or interface type"
|
||||
return false
|
||||
}
|
||||
case *Pointer, *Interface:
|
||||
err = "pointer or interface type"
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return true
|
||||
})
|
||||
}
|
||||
case *Basic:
|
||||
err = "basic or unnamed type"
|
||||
if compilerErrorMessages {
|
||||
check.errorf(recv, _InvalidRecv, "cannot define new methods on non-local type %s", recv.typ)
|
||||
err = ""
|
||||
}
|
||||
default:
|
||||
check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ)
|
||||
}
|
||||
if err != "" {
|
||||
check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err)
|
||||
}
|
||||
case *Basic:
|
||||
err = "basic or unnamed type"
|
||||
default:
|
||||
check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ)
|
||||
}
|
||||
if err != "" {
|
||||
check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err)
|
||||
// ok to continue
|
||||
}
|
||||
}
|
||||
sig.recv = recv
|
||||
}).describef(recv, "validate receiver %s", recv)
|
||||
}
|
||||
|
||||
sig.params = NewTuple(params...)
|
||||
|
|
|
|||
|
|
@ -160,7 +160,10 @@ func (subst *subster) typ(typ Type) Type {
|
|||
methods, mcopied := subst.funcList(t.methods)
|
||||
embeddeds, ecopied := subst.typeList(t.embeddeds)
|
||||
if mcopied || ecopied {
|
||||
iface := &Interface{embeddeds: embeddeds, implicit: t.implicit, complete: t.complete}
|
||||
iface := subst.check.newInterface()
|
||||
iface.embeddeds = embeddeds
|
||||
iface.implicit = t.implicit
|
||||
iface.complete = t.complete
|
||||
// If we've changed the interface type, we may need to replace its
|
||||
// receiver if the receiver type is the original interface. Receivers of
|
||||
// *Named type are replaced during named type expansion.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type RC[RG any] interface {
|
||||
~[]RG
|
||||
}
|
||||
|
||||
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||
|
||||
type F[RCT RC[RG], RG any] interface {
|
||||
Fn() Fn[RCT]
|
||||
}
|
||||
|
||||
type concreteF[RCT RC[RG], RG any] struct {
|
||||
makeFn func() Fn[RCT]
|
||||
}
|
||||
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||
return c.makeFn()
|
||||
}
|
||||
|
||||
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
|
||||
return &concreteF[RCT]{
|
||||
makeFn: nil,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type RC[RG any] interface {
|
||||
~[]RG
|
||||
}
|
||||
|
||||
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||
|
||||
type FFn[RCT RC[RG], RG any] func() Fn[RCT]
|
||||
|
||||
type F[RCT RC[RG], RG any] interface {
|
||||
Fn() Fn[RCT]
|
||||
}
|
||||
|
||||
type concreteF[RCT RC[RG], RG any] struct {
|
||||
makeFn FFn[RCT]
|
||||
}
|
||||
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||
return c.makeFn()
|
||||
}
|
||||
|
|
@ -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},
|
||||
})
|
||||
}
|
||||
|
|
@ -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 */ }}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file is tested when running "go test -run Manual"
|
||||
// without source arguments. Use for one-off debugging.
|
||||
|
||||
package p
|
||||
|
||||
type T[P any, B *P] struct{}
|
||||
|
||||
func (T /* ERROR cannot use generic type */ ) m0() {}
|
||||
func (/* ERROR got 1 type parameter, but receiver base type declares 2 */ T[_]) m1() {}
|
||||
func (T[_, _]) m2() {}
|
||||
// TODO(gri) this error is unfortunate (issue #51343)
|
||||
func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
func _() {
|
||||
len.Println /* ERROR cannot select on len */
|
||||
len.Println /* ERROR cannot select on len */ ()
|
||||
_ = len.Println /* ERROR cannot select on len */
|
||||
_ = len /* ERROR cannot index len */ [0]
|
||||
_ = *len /* ERROR cannot indirect len */
|
||||
}
|
||||
|
|
@ -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("")
|
||||
}
|
||||
|
|
@ -7,9 +7,7 @@ package types
|
|||
// A Type represents a type of Go.
|
||||
// All types implement the Type interface.
|
||||
type Type interface {
|
||||
// Underlying returns the underlying type of a type
|
||||
// w/o following forwarding chains. Only used by
|
||||
// client packages.
|
||||
// Underlying returns the underlying type of a type.
|
||||
Underlying() Type
|
||||
|
||||
// String returns a string representation of a type.
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ func NewTypeParam(obj *TypeName, constraint Type) *TypeParam {
|
|||
return (*Checker)(nil).newTypeParam(obj, constraint)
|
||||
}
|
||||
|
||||
// check may be nil
|
||||
func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
|
||||
// Always increment lastID, even if it is not used.
|
||||
id := nextID()
|
||||
|
|
@ -49,9 +50,7 @@ func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
|
|||
// iface may mutate typ.bound, so we must ensure that iface() is called
|
||||
// at least once before the resulting TypeParam escapes.
|
||||
if check != nil {
|
||||
check.later(func() {
|
||||
typ.iface()
|
||||
})
|
||||
check.needsCleanup(typ)
|
||||
} else if constraint != nil {
|
||||
typ.iface()
|
||||
}
|
||||
|
|
@ -95,9 +94,12 @@ func (t *TypeParam) String() string { return TypeString(t, nil) }
|
|||
// ----------------------------------------------------------------------------
|
||||
// Implementation
|
||||
|
||||
func (t *TypeParam) cleanup() {
|
||||
t.iface()
|
||||
t.check = nil
|
||||
}
|
||||
|
||||
// iface returns the constraint interface of t.
|
||||
// TODO(gri) If we make tparamIsIface the default, this should be renamed to under
|
||||
// (similar to Named.under).
|
||||
func (t *TypeParam) iface() *Interface {
|
||||
bound := t.bound
|
||||
|
||||
|
|
@ -138,16 +140,6 @@ func (t *TypeParam) iface() *Interface {
|
|||
return ityp
|
||||
}
|
||||
|
||||
// singleType returns the single type of the type parameter constraint; or nil.
|
||||
func (t *TypeParam) singleType() Type {
|
||||
return t.iface().typeSet().singleType()
|
||||
}
|
||||
|
||||
// hasTerms reports whether the type parameter constraint has specific type terms.
|
||||
func (t *TypeParam) hasTerms() bool {
|
||||
return t.iface().typeSet().hasTerms()
|
||||
}
|
||||
|
||||
// is calls f with the specific type terms of t's constraint and reports whether
|
||||
// all calls to f returned true. If there are no specific terms, is
|
||||
// returns the result of f(nil).
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ func (s *_TypeSet) IsComparable(seen map[Type]bool) bool {
|
|||
return s.comparable
|
||||
}
|
||||
return s.is(func(t *term) bool {
|
||||
return t != nil && comparable(t.typ, seen, nil)
|
||||
return t != nil && comparable(t.typ, false, seen, nil)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -101,9 +101,6 @@ func (s *_TypeSet) String() string {
|
|||
// hasTerms reports whether the type set has specific type terms.
|
||||
func (s *_TypeSet) hasTerms() bool { return !s.terms.isEmpty() && !s.terms.isAll() }
|
||||
|
||||
// singleType returns the single type in s if there is exactly one; otherwise the result is nil.
|
||||
func (s *_TypeSet) singleType() Type { return s.terms.singleType() }
|
||||
|
||||
// subsetOf reports whether s1 ⊆ s2.
|
||||
func (s1 *_TypeSet) subsetOf(s2 *_TypeSet) bool { return s1.terms.subsetOf(s2.terms) }
|
||||
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) {
|
|||
return typ
|
||||
|
||||
case *ast.InterfaceType:
|
||||
typ := new(Interface)
|
||||
typ := check.newInterface()
|
||||
def.setUnderlying(typ)
|
||||
if def != nil {
|
||||
typ.obj = def.obj
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ func (check *Checker) validType0(typ Type, env *tparamEnv, path []Object) typeIn
|
|||
// would have reported a type cycle and couldn't have been
|
||||
// imported in the first place.
|
||||
assert(t.obj.pkg == check.pkg)
|
||||
t.underlying = Typ[Invalid] // t is in the current package (no race possibilty)
|
||||
t.underlying = Typ[Invalid] // t is in the current package (no race possibility)
|
||||
// Find the starting point of the cycle and report it.
|
||||
for i, tn := range path {
|
||||
if tn == t.obj {
|
||||
|
|
|
|||
|
|
@ -703,6 +703,12 @@ var (
|
|||
_ io.Reader = (*Buffers)(nil)
|
||||
)
|
||||
|
||||
// WriteTo writes contents of the buffers to w.
|
||||
//
|
||||
// WriteTo implements io.WriterTo for Buffers.
|
||||
//
|
||||
// WriteTo modifies the slice v as well as v[i] for 0 <= i < len(v),
|
||||
// but does not modify v[i][j] for any i, j.
|
||||
func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) {
|
||||
if wv, ok := w.(buffersWriter); ok {
|
||||
return wv.writeBuffers(v)
|
||||
|
|
@ -719,6 +725,12 @@ func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) {
|
|||
return n, nil
|
||||
}
|
||||
|
||||
// Read from the buffers.
|
||||
//
|
||||
// Read implements io.Reader for Buffers.
|
||||
//
|
||||
// Read modifies the slice v as well as v[i] for 0 <= i < len(v),
|
||||
// but does not modify v[i][j] for any i, j.
|
||||
func (v *Buffers) Read(p []byte) (n int, err error) {
|
||||
for len(p) > 0 && len(*v) > 0 {
|
||||
n0 := copy(p, (*v)[0])
|
||||
|
|
|
|||
|
|
@ -33,9 +33,14 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$432
|
|||
ADD $LOCAL_REGARGS, RSP, R20
|
||||
CALL runtime·spillArgs(SB)
|
||||
MOVD R26, 32(RSP) // outside of moveMakeFuncArgPtrs's arg area
|
||||
#ifdef GOEXPERIMENT_regabiargs
|
||||
MOVD R26, R0
|
||||
MOVD R20, R1
|
||||
#else
|
||||
MOVD R26, 8(RSP)
|
||||
MOVD R20, 16(RSP)
|
||||
CALL ·moveMakeFuncArgPtrs(SB)
|
||||
#endif
|
||||
CALL ·moveMakeFuncArgPtrs<ABIInternal>(SB)
|
||||
MOVD 32(RSP), R26
|
||||
MOVD R26, 8(RSP)
|
||||
MOVD $argframe+0(FP), R3
|
||||
|
|
@ -61,9 +66,14 @@ TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$432
|
|||
ADD $LOCAL_REGARGS, RSP, R20
|
||||
CALL runtime·spillArgs(SB)
|
||||
MOVD R26, 32(RSP) // outside of moveMakeFuncArgPtrs's arg area
|
||||
#ifdef GOEXPERIMENT_regabiargs
|
||||
MOVD R26, R0
|
||||
MOVD R20, R1
|
||||
#else
|
||||
MOVD R26, 8(RSP)
|
||||
MOVD R20, 16(RSP)
|
||||
CALL ·moveMakeFuncArgPtrs(SB)
|
||||
#endif
|
||||
CALL ·moveMakeFuncArgPtrs<ABIInternal>(SB)
|
||||
MOVD 32(RSP), R26
|
||||
MOVD R26, 8(RSP)
|
||||
MOVD $argframe+0(FP), R3
|
||||
|
|
|
|||
|
|
@ -229,16 +229,22 @@ store64loop:
|
|||
// functions tail-call into the appropriate implementation, which
|
||||
// means they must not open a frame. Hence, when they go down the
|
||||
// panic path, at that point they push the LR to create a real frame
|
||||
// (they don't need to pop it because panic won't return).
|
||||
// (they don't need to pop it because panic won't return; however, we
|
||||
// do need to set the SP delta back).
|
||||
|
||||
// Check if R1 is 8-byte aligned, panic if not.
|
||||
// Clobbers R2.
|
||||
#define CHECK_ALIGN \
|
||||
AND.S $7, R1, R2 \
|
||||
BEQ 4(PC) \
|
||||
MOVW.W R14, -4(R13) /* prepare a real frame */ \
|
||||
BL ·panicUnaligned(SB) \
|
||||
ADD $4, R13 /* compensate SP delta */
|
||||
|
||||
TEXT ·Cas64(SB),NOSPLIT,$-4-21
|
||||
NO_LOCAL_POINTERS
|
||||
MOVW addr+0(FP), R1
|
||||
// make unaligned atomic access panic
|
||||
AND.S $7, R1, R2
|
||||
BEQ 3(PC)
|
||||
MOVW.W R14, -4(R13) // prepare a real frame
|
||||
BL ·panicUnaligned(SB)
|
||||
CHECK_ALIGN
|
||||
|
||||
MOVB runtime·goarm(SB), R11
|
||||
CMP $7, R11
|
||||
|
|
@ -249,11 +255,7 @@ TEXT ·Cas64(SB),NOSPLIT,$-4-21
|
|||
TEXT ·Xadd64(SB),NOSPLIT,$-4-20
|
||||
NO_LOCAL_POINTERS
|
||||
MOVW addr+0(FP), R1
|
||||
// make unaligned atomic access panic
|
||||
AND.S $7, R1, R2
|
||||
BEQ 3(PC)
|
||||
MOVW.W R14, -4(R13) // prepare a real frame
|
||||
BL ·panicUnaligned(SB)
|
||||
CHECK_ALIGN
|
||||
|
||||
MOVB runtime·goarm(SB), R11
|
||||
CMP $7, R11
|
||||
|
|
@ -264,11 +266,7 @@ TEXT ·Xadd64(SB),NOSPLIT,$-4-20
|
|||
TEXT ·Xchg64(SB),NOSPLIT,$-4-20
|
||||
NO_LOCAL_POINTERS
|
||||
MOVW addr+0(FP), R1
|
||||
// make unaligned atomic access panic
|
||||
AND.S $7, R1, R2
|
||||
BEQ 3(PC)
|
||||
MOVW.W R14, -4(R13) // prepare a real frame
|
||||
BL ·panicUnaligned(SB)
|
||||
CHECK_ALIGN
|
||||
|
||||
MOVB runtime·goarm(SB), R11
|
||||
CMP $7, R11
|
||||
|
|
@ -279,11 +277,7 @@ TEXT ·Xchg64(SB),NOSPLIT,$-4-20
|
|||
TEXT ·Load64(SB),NOSPLIT,$-4-12
|
||||
NO_LOCAL_POINTERS
|
||||
MOVW addr+0(FP), R1
|
||||
// make unaligned atomic access panic
|
||||
AND.S $7, R1, R2
|
||||
BEQ 3(PC)
|
||||
MOVW.W R14, -4(R13) // prepare a real frame
|
||||
BL ·panicUnaligned(SB)
|
||||
CHECK_ALIGN
|
||||
|
||||
MOVB runtime·goarm(SB), R11
|
||||
CMP $7, R11
|
||||
|
|
@ -294,11 +288,7 @@ TEXT ·Load64(SB),NOSPLIT,$-4-12
|
|||
TEXT ·Store64(SB),NOSPLIT,$-4-12
|
||||
NO_LOCAL_POINTERS
|
||||
MOVW addr+0(FP), R1
|
||||
// make unaligned atomic access panic
|
||||
AND.S $7, R1, R2
|
||||
BEQ 3(PC)
|
||||
MOVW.W R14, -4(R13) // prepare a real frame
|
||||
BL ·panicUnaligned(SB)
|
||||
CHECK_ALIGN
|
||||
|
||||
MOVB runtime·goarm(SB), R11
|
||||
CMP $7, R11
|
||||
|
|
|
|||
|
|
@ -188,8 +188,12 @@ ret:
|
|||
|
||||
// func runtime·racefuncenter(pc uintptr)
|
||||
// Called from instrumented code.
|
||||
TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8
|
||||
TEXT runtime·racefuncenter<ABIInternal>(SB), NOSPLIT, $0-8
|
||||
#ifdef GOEXPERIMENT_regabiargs
|
||||
MOVD R0, R9 // callpc
|
||||
#else
|
||||
MOVD callpc+0(FP), R9
|
||||
#endif
|
||||
JMP racefuncenter<>(SB)
|
||||
|
||||
// Common code for racefuncenter
|
||||
|
|
@ -205,7 +209,7 @@ TEXT racefuncenter<>(SB), NOSPLIT, $0-0
|
|||
|
||||
// func runtime·racefuncexit()
|
||||
// Called from instrumented code.
|
||||
TEXT runtime·racefuncexit(SB), NOSPLIT, $0-0
|
||||
TEXT runtime·racefuncexit<ABIInternal>(SB), NOSPLIT, $0-0
|
||||
load_g
|
||||
MOVD g_racectx(g), R0 // race context
|
||||
// void __tsan_func_exit(ThreadState *thr);
|
||||
|
|
@ -392,12 +396,12 @@ racecallatomic_ignore:
|
|||
// Addr is outside the good range.
|
||||
// Call __tsan_go_ignore_sync_begin to ignore synchronization during the atomic op.
|
||||
// An attempt to synchronize on the address would cause crash.
|
||||
MOVD R9, R20 // remember the original function
|
||||
MOVD R9, R21 // remember the original function
|
||||
MOVD $__tsan_go_ignore_sync_begin(SB), R9
|
||||
load_g
|
||||
MOVD g_racectx(g), R0 // goroutine context
|
||||
BL racecall<>(SB)
|
||||
MOVD R20, R9 // restore the original function
|
||||
MOVD R21, R9 // restore the original function
|
||||
// Call the atomic function.
|
||||
// racecall will call LLVM race code which might clobber R28 (g)
|
||||
load_g
|
||||
|
|
@ -424,10 +428,12 @@ TEXT runtime·racecall(SB), NOSPLIT, $0-0
|
|||
JMP racecall<>(SB)
|
||||
|
||||
// Switches SP to g0 stack and calls (R9). Arguments already set.
|
||||
TEXT racecall<>(SB), NOSPLIT, $0-0
|
||||
// Clobbers R19, R20.
|
||||
TEXT racecall<>(SB), NOSPLIT|NOFRAME, $0-0
|
||||
MOVD g_m(g), R10
|
||||
// Switch to g0 stack.
|
||||
MOVD RSP, R19 // callee-saved, preserved across the CALL
|
||||
MOVD R30, R20 // callee-saved, preserved across the CALL
|
||||
MOVD m_g0(R10), R11
|
||||
CMP R11, g
|
||||
BEQ call // already on g0
|
||||
|
|
@ -436,7 +442,7 @@ TEXT racecall<>(SB), NOSPLIT, $0-0
|
|||
call:
|
||||
BL R9
|
||||
MOVD R19, RSP
|
||||
RET
|
||||
JMP (R20)
|
||||
|
||||
// C->Go callback thunk that allows to call runtime·racesymbolize from C code.
|
||||
// Direct Go->C race call has only switched SP, finish g->g0 switch by setting correct g.
|
||||
|
|
|
|||
|
|
@ -17,87 +17,91 @@ import (
|
|||
|
||||
//go:linkname syscall_syscall syscall.syscall
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
|
||||
args := struct{ fn, a1, a2, a3, r1, r2, err uintptr }{fn, a1, a2, a3, r1, r2, err}
|
||||
entersyscall()
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall)), unsafe.Pointer(&fn))
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall)), unsafe.Pointer(&args))
|
||||
exitsyscall()
|
||||
return
|
||||
return args.r1, args.r2, args.err
|
||||
}
|
||||
func syscall()
|
||||
|
||||
//go:linkname syscall_syscallX syscall.syscallX
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func syscall_syscallX(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
|
||||
args := struct{ fn, a1, a2, a3, r1, r2, err uintptr }{fn, a1, a2, a3, r1, r2, err}
|
||||
entersyscall()
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscallX)), unsafe.Pointer(&fn))
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscallX)), unsafe.Pointer(&args))
|
||||
exitsyscall()
|
||||
return
|
||||
return args.r1, args.r2, args.err
|
||||
}
|
||||
func syscallX()
|
||||
|
||||
//go:linkname syscall_syscall6 syscall.syscall6
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
|
||||
args := struct{ fn, a1, a2, a3, a4, a5, a6, r1, r2, err uintptr }{fn, a1, a2, a3, a4, a5, a6, r1, r2, err}
|
||||
entersyscall()
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6)), unsafe.Pointer(&fn))
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6)), unsafe.Pointer(&args))
|
||||
exitsyscall()
|
||||
return
|
||||
return args.r1, args.r2, args.err
|
||||
}
|
||||
func syscall6()
|
||||
|
||||
//go:linkname syscall_syscall6X syscall.syscall6X
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
|
||||
args := struct{ fn, a1, a2, a3, a4, a5, a6, r1, r2, err uintptr }{fn, a1, a2, a3, a4, a5, a6, r1, r2, err}
|
||||
entersyscall()
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6X)), unsafe.Pointer(&fn))
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6X)), unsafe.Pointer(&args))
|
||||
exitsyscall()
|
||||
return
|
||||
return args.r1, args.r2, args.err
|
||||
}
|
||||
func syscall6X()
|
||||
|
||||
//go:linkname syscall_syscallPtr syscall.syscallPtr
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func syscall_syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
|
||||
args := struct{ fn, a1, a2, a3, r1, r2, err uintptr }{fn, a1, a2, a3, r1, r2, err}
|
||||
entersyscall()
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscallPtr)), unsafe.Pointer(&fn))
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscallPtr)), unsafe.Pointer(&args))
|
||||
exitsyscall()
|
||||
return
|
||||
return args.r1, args.r2, args.err
|
||||
}
|
||||
func syscallPtr()
|
||||
|
||||
//go:linkname syscall_rawSyscall syscall.rawSyscall
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall)), unsafe.Pointer(&fn))
|
||||
return
|
||||
args := struct{ fn, a1, a2, a3, r1, r2, err uintptr }{fn, a1, a2, a3, r1, r2, err}
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall)), unsafe.Pointer(&args))
|
||||
return args.r1, args.r2, args.err
|
||||
}
|
||||
|
||||
//go:linkname syscall_rawSyscall6 syscall.rawSyscall6
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6)), unsafe.Pointer(&fn))
|
||||
return
|
||||
args := struct{ fn, a1, a2, a3, a4, a5, a6, r1, r2, err uintptr }{fn, a1, a2, a3, a4, a5, a6, r1, r2, err}
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall6)), unsafe.Pointer(&args))
|
||||
return args.r1, args.r2, args.err
|
||||
}
|
||||
|
||||
// syscallNoErr is used in crypto/x509 to call into Security.framework and CF.
|
||||
|
||||
//go:linkname crypto_x509_syscall crypto/x509/internal/macos.syscall
|
||||
//go:nosplit
|
||||
//go:cgo_unsafe_args
|
||||
func crypto_x509_syscall(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1 uintptr) {
|
||||
func crypto_x509_syscall(fn, a1, a2, a3, a4, a5 uintptr, f1 float64) (r1 uintptr) {
|
||||
args := struct {
|
||||
fn, a1, a2, a3, a4, a5 uintptr
|
||||
f1 float64
|
||||
r1 uintptr
|
||||
}{fn, a1, a2, a3, a4, a5, f1, r1}
|
||||
entersyscall()
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscallNoErr)), unsafe.Pointer(&fn))
|
||||
libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall_x509)), unsafe.Pointer(&args))
|
||||
exitsyscall()
|
||||
return
|
||||
return args.r1
|
||||
}
|
||||
func syscallNoErr()
|
||||
func syscall_x509()
|
||||
|
||||
// The *_trampoline functions convert from the Go calling convention to the C calling convention
|
||||
// and then call the underlying libc function. They are defined in sys_darwin_$ARCH.s.
|
||||
|
|
|
|||
|
|
@ -831,9 +831,10 @@ ok:
|
|||
POPQ BP
|
||||
RET
|
||||
|
||||
// syscallNoErr is like syscall6 but does not check for errors, and
|
||||
// only returns one value, for use with standard C ABI library functions.
|
||||
TEXT runtime·syscallNoErr(SB),NOSPLIT,$0
|
||||
// syscall_x509 is for crypto/x509. It is like syscall6 but does not check for errors,
|
||||
// takes 5 uintptrs and 1 float64, and only returns one value,
|
||||
// for use with standard C ABI functions.
|
||||
TEXT runtime·syscall_x509(SB),NOSPLIT,$0
|
||||
PUSHQ BP
|
||||
MOVQ SP, BP
|
||||
SUBQ $16, SP
|
||||
|
|
@ -842,7 +843,7 @@ TEXT runtime·syscallNoErr(SB),NOSPLIT,$0
|
|||
MOVQ (3*8)(DI), DX // a3
|
||||
MOVQ (4*8)(DI), CX // a4
|
||||
MOVQ (5*8)(DI), R8 // a5
|
||||
MOVQ (6*8)(DI), R9 // a6
|
||||
MOVQ (6*8)(DI), X0 // f1
|
||||
MOVQ DI, (SP)
|
||||
MOVQ (1*8)(DI), DI // a1
|
||||
XORL AX, AX // vararg: say "no float args"
|
||||
|
|
|
|||
|
|
@ -736,9 +736,10 @@ TEXT runtime·syscall6X(SB),NOSPLIT,$0
|
|||
ok:
|
||||
RET
|
||||
|
||||
// syscallNoErr is like syscall6 but does not check for errors, and
|
||||
// only returns one value, for use with standard C ABI library functions.
|
||||
TEXT runtime·syscallNoErr(SB),NOSPLIT,$0
|
||||
// syscall_x509 is for crypto/x509. It is like syscall6 but does not check for errors,
|
||||
// takes 5 uintptrs and 1 float64, and only returns one value,
|
||||
// for use with standard C ABI functions.
|
||||
TEXT runtime·syscall_x509(SB),NOSPLIT,$0
|
||||
SUB $16, RSP // push structure pointer
|
||||
MOVD R0, (RSP)
|
||||
|
||||
|
|
@ -747,7 +748,7 @@ TEXT runtime·syscallNoErr(SB),NOSPLIT,$0
|
|||
MOVD 24(R0), R2 // a3
|
||||
MOVD 32(R0), R3 // a4
|
||||
MOVD 40(R0), R4 // a5
|
||||
MOVD 48(R0), R5 // a6
|
||||
FMOVD 48(R0), F0 // f1
|
||||
MOVD 8(R0), R0 // a1
|
||||
BL (R12)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ package main
|
|||
// This is a regression test for issue 14599, where profiling fails when the
|
||||
// function is the first C function. Exported functions are the first C
|
||||
// functions, so we use an exported function. Exported functions are created in
|
||||
// lexigraphical order of source files, so this file is named aprof.go to
|
||||
// lexicographical order of source files, so this file is named aprof.go to
|
||||
// ensure its function is first.
|
||||
|
||||
// extern void CallGoNop();
|
||||
|
|
|
|||
|
|
@ -17,10 +17,9 @@ type Builder struct {
|
|||
buf []byte
|
||||
}
|
||||
|
||||
// noescape hides a pointer from escape analysis. noescape is
|
||||
// the identity function but escape analysis doesn't think the
|
||||
// output depends on the input. noescape is inlined and currently
|
||||
// compiles down to zero instructions.
|
||||
// noescape hides a pointer from escape analysis. It is the identity function
|
||||
// but escape analysis doesn't think the output depends on the input.
|
||||
// noescape is inlined and currently compiles down to zero instructions.
|
||||
// USE CAREFULLY!
|
||||
// This was copied from the runtime; see issues 23382 and 7921.
|
||||
//go:nosplit
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package a
|
||||
|
||||
// Type I is the first basic test for the issue, which relates to a type that is recursive
|
||||
// via a type constraint. (In this test, I -> IConstraint -> MyStruct -> I.)
|
||||
type JsonRaw []byte
|
||||
|
||||
type MyStruct struct {
|
||||
x *I[JsonRaw]
|
||||
}
|
||||
|
||||
type IConstraint interface {
|
||||
JsonRaw | MyStruct
|
||||
}
|
||||
|
||||
type I[T IConstraint] struct {
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"a"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var x a.I[a.JsonRaw]
|
||||
|
||||
fmt.Printf("%v\n", x)
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// rundir -G=3
|
||||
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ignored
|
||||
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package a
|
||||
|
||||
type Interaction[DataT InteractionDataConstraint] struct {
|
||||
}
|
||||
|
||||
type InteractionDataConstraint interface {
|
||||
[]byte |
|
||||
UserCommandInteractionData
|
||||
}
|
||||
|
||||
type UserCommandInteractionData struct {
|
||||
resolvedInteractionWithOptions
|
||||
}
|
||||
|
||||
type resolvedInteractionWithOptions struct {
|
||||
Resolved Resolved `json:"resolved,omitempty"`
|
||||
}
|
||||
|
||||
type Resolved struct {
|
||||
Users ResolvedData[User] `json:"users,omitempty"`
|
||||
}
|
||||
|
||||
type ResolvedData[T ResolvedDataConstraint] map[uint64]T
|
||||
|
||||
type ResolvedDataConstraint interface {
|
||||
User | Message
|
||||
}
|
||||
|
||||
type User struct{}
|
||||
|
||||
type Message struct {
|
||||
Interaction *Interaction[[]byte] `json:"interaction,omitempty"`
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package b
|
||||
|
||||
import (
|
||||
"./a"
|
||||
)
|
||||
|
||||
// InteractionRequest is an incoming request Interaction
|
||||
type InteractionRequest[T a.InteractionDataConstraint] struct {
|
||||
a.Interaction[T]
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
import (
|
||||
"./b"
|
||||
)
|
||||
|
||||
// ResponseWriterMock mocks corde's ResponseWriter interface
|
||||
type ResponseWriterMock struct {
|
||||
x b.InteractionRequest[[]byte]
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// compiledir -G=3
|
||||
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ignored
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// compile -G=3
|
||||
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type RC[RG any] interface {
|
||||
~[]RG
|
||||
}
|
||||
|
||||
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||
|
||||
type F[RCT RC[RG], RG any] interface {
|
||||
Fn() Fn[RCT]
|
||||
}
|
||||
|
||||
type concreteF[RCT RC[RG], RG any] struct {
|
||||
makeFn func() Fn[RCT]
|
||||
}
|
||||
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||
return c.makeFn()
|
||||
}
|
||||
|
||||
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
|
||||
return &concreteF[RCT]{
|
||||
makeFn: nil,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// compile -G=3
|
||||
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
package p
|
||||
|
||||
type RC[RG any] interface {
|
||||
~[]RG
|
||||
}
|
||||
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||
type FFn[RCT RC[RG], RG any] func() Fn[RCT]
|
||||
type F[RCT RC[RG], RG any] interface {
|
||||
Fn() Fn[RCT]
|
||||
}
|
||||
type concreteF[RCT RC[RG], RG any] struct {
|
||||
makeFn FFn[RCT]
|
||||
}
|
||||
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||
return c.makeFn()
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue